Keep on moving

あんまりまとまってないことを書きますよ

Python3.7のPEP 563: Postponed evaluation of annotations はいいもんだなっていう話

大家好, レアキャラです。 今日はPython3.7の新機能 で気になってるやつを紹介したいと思います。

TL;DR

version
Python 3.6.4, 3.7b2
mypy 0.580

Python3.7で __future__annotations ってのが追加されて、TypeHintの痒いところに手が届くようになる。

PEP 563 -- Postponed Evaluation of Annotations | Python.org

Python 3.7での変更点

ドキュメントにも書いてあるんですが、軽くコードで書くと

What’s New In Python 3.7 — Python 3.8.0a0 documentation

class C:
    @classmethod
    def from_string(cls, source: str) -> C: # クラス内で自分自身のクラス(この場合 `C`)が使えるように
        ...

    def validate_b(self, obj: B) -> bool: # クラスBが定義される前でも使えるように
        ...

class B:
    ...

class だとこんな感じで結構制約があったのが変更されるようになります。 一個例を上げときます。例えばこんな感じのコードです。

# -*- coding: utf-8 -*-

class Meter:
    def __init__(self, value: int) -> None:
        self.value = value
    def add(self, other:Meter) -> None: # Python3.6だと実行時にここがエラーになる
        self.value += other.value

a = Meter(1)
b = Meter(2)
a.add(b)
print(a.value)
$ python3.6 add.py
Traceback (most recent call last):
  File "add.py", line 5, in <module>
    class Meter:
  File "add.py", line 8, in Meter
    def add(self, other:Meter) -> None:
NameError: name 'Meter' is not defined

このコードは Python3.6では、実行時エラーになります。クラス内で自分のクラスがTypeHints として使えないからです。(1) 3.7ではこれがfrom __future__ import annotations を使うことで動かせるようになります。

# -*- coding: utf-8 -*-
# from __future__ import annotations


class Meter:
    def __init__(self, value: int) -> None:
        self.value = value
    def add(self, other:Meter) -> None:
        self.value += other.value

a = Meter(1)
b = Meter(2)
a.add(b)
print(a.value)
$ python3.7 add.py
3

futureをつけないとPython3.6と同じで実行時エラーになります.これは互換性に配慮した変更です。 ちなみにこれは Python4.0でデフォルトの挙動になります。 Python3系で future が増えるのは久しぶりです。直感的にわかりやすくかけるので個人的にはなかなかいい変更ダナーと思います。


  1. ちなみに mypy(0.580) ではこれがエラーになりません。実装系ごとの違いなのかもです

2017振り返り

こんにちは, レアキャラです。

今年もあんまりブログ書けなかったなーとか思いつつ今年のことをまとめておきます。 今年は割と外で話したりしたなーとか思いつつ。

発表

Python 3.6 リリースパーティー

pystudy.connpass.com

Pythonの有名人たちの中で発表したのですごい緊張したのを覚えています。 何しろ僕以外の発表者みなさん、Python本の著者だったんですよねー 個人的にめっちゃ興味のあったPythonでのtype-hintingについて話しました

www.slideshare.net

PyCon Taiwan 2017

PyCon Taiwan 2017

これ実はPython 3.6 リリースパーティー で使ったネタを話す予定だったんですが、 いろいろ考えてほぼ書き下ろしみたいなネタになりました。 初海外での発表で、all英語で30分。CfPから英語でなんかすごいことになっちゃったなーとか思いながら用意しました。 ちなみにスライド作成はなんだかんだで1ヶ月かかりました。ここの話はよく考えると公開してないので、あとでちゃんと書こうと思います!

www.slideshare.net

実はPyConJPでもちょいと話した

今年はTalkの方はAcceptしてもらえなかったので、ちょっと他の形で発表しました。 英語未だに苦手意識が消えないんですが、日々の業務と英語の話しを割とできたかなーと。 あと、ここも僕以外の発表者はすごい人だらけだったのでえらい緊張しました。

weekly.ascii.jp

PythonBootCampFukuoka

pyconjp.blogspot.jp

縁あって福岡のBootCampでTAをやってきました。福岡の皆さん勉強熱心ですげーなと思いました。 あと清水川さんと一緒に外でイベントで来て、楽しかったです。

以上、来年の目標はまた来年でー、皆様良いお年を!

GradleでScalaのインクリメンタルコンパイラのバージョンを変える

|Gradle|4.3.1|

GradleのScala plugin 使うと Zinc Compiler がすでに有効になっていて インクリメンタルにコンパイルしてくれる(=== 全コンパイルしない)

https://docs.gradle.org/current/userguide/scala_plugin.html#sec:configure_zinc_compiler

ちなみにバージョンを上げたい場合は以下のようにdependencyに追加するだけ

dependencies {
    zinc 'com.typesafe.zinc:zinc:0.3.9'
}

ちなみに

Zinc 1.0系にはまだGradleでは対応してないようです

github.com

Gradleの方でもissue化されてる。インターフェースがコレまでと違うらしく違う名前(scala-plugin じゃない名前)になるかもとのこと。今後に期待

github.com

GradleでScala projectをはじめる

近頃Scalaを学び始めるのにどうやると学びはじめやすいのかと考えることが多いです。 すでにJavaを知っているならば覚えることが少ないほうがいいよなーと思ってるので、ひとまず Gradleから始める方法をまとめておこうと思います

update 2017.11.05
Gradle 4.3
Scala 2.12.x

TL;DR

Gradle Scala-plugin超便利、sbtでできている差分コンパイル相当もできる

The Scala Plugin - Gradle User Guide Version 4.3

Gradle Scala plugin

Gradleをまずはインストールします。

Installing Gradle - Gradle User Guide Version 4.3

フォルダをつくって以下のコマンドを実行するだけでScalaのフォルダ構成とbuild.gradleを生成してくれます。

$ cd path/to/src
$ mkdir gradle-scala
$ gradle init --type scala-library
 tree
.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   └── scala
    │       └── Library.scala
    └── test
        └── scala
            └── LibrarySuite.scala

minimum 構成

ちなみにbuild.gradleの記述量をなるべく少なくしたい場合はこんな感じでOK

gist.github.com

scala repl on gradle

gradleから scala reple が使いたいときはこんな感じでいいみたい

stackoverflow.com

以下の様にscala-compilerも入れることでreplタスクが使える

dependencies{
  compile "org.scala-lang:scala-library:2.11.7"
  compile "org.scala-lang:scala-compiler:2.11.7"
}

task repl(type:JavaExec) {
  main = "scala.tools.nsc.MainGenericRunner"
  classpath = sourceSets.main.runtimeClasspath
  standardInput System.in
  args '-usejavacp'
}

あとは以下の様に起動できます

gradle repl --console plain --no-daemon

Please Try It!

scalafmt の設定ファイルのおすすめ最小構成(2017.10)

package version
scalafmt 1.3.0

皆さんScalaでもコードフォーマットツール使ってますか? 僕はscalafmtを愛用しています。

http://scalameta.org/scalafmt/

goのgofmtみたいなものなんですが、設定ファイルでフォーマットの条件をいじれます。 設定しなくてもいいんですが、まだたまーに 互換性のないアップデートがあったりするので 個人的には設定ファイルをつくっておくのをおすすめしています。 で、最小構成の設定ファイルを毎回作るので、一旦まとめてみました。

最小構成

僕はプロジェクトに追加するときはひとまずファイルをつくっています。 ちなみにプロジェクトのroot direcotory に .scalafmt.conf と言う名前で作ります。

# Only format files tracked by git.
project.git = true # Default: false
# Manually exclude files to format.
project.excludeFilters = ["target/"]
#
# maxColumn = 100 # Default: 80
  • project がgitだったら project.git=trueは入れましょう。gitによって追跡されるファイルのみがフォーマット対象になります
  • target配下は外していいと思います
  • maxColumnは好きな値をいれると良いでしょう。こだわりがなければ80文字で良いかと。github mobileとかでも読みやすくなるそうな。

その他

  • Q:既存のプロジェクトにフォーマットを崩さないように追加したい場合は?
  • A: KKK(Kiai/Konjou/Konki) でオプションを駆使して頑張ってください!!

参考

Scalafmt - code formatter for Scala

qiita.com

dockerで実行するときにulimitを設定する

software version
docker 17.09

dockerを使ってUnitTest実行したいときってありますよね? でもファイルとかソケットをもりもり開く処理がおおいとosのopen filesの上限を超えちゃうことってありますよね?(ホントか?)

普通にOSのせっていだったら以下のようにすればいい

ulimit -n 12345

ではdockerだとどうなのよってことで調べました。今は docker run のときのオプションで設定できるらしい

docs.docker.com

docker run --ulimit nofile=12345:12345 <image-tag>

うーんdocker containerを作り直さなくていいので楽でいいですね。

先人に感謝

小規模なライブラリでのJUnit5 migration方法

JUnit 5がついにリリースされましたね。

後方互換性がなくなったこともあって、使い方を覚えたくなって私の自作ボットエンジン(Java版のHubot的なもの)をJUnit5で動くようにマイグレーションしてみました。

TL:DR

github.com

題材

GitHub - masahitojp/botan-core: tiny chat bot framework for Java SE 8.(like a Hubot)

Java8 Lambdaでパフォーマンスがどれくらい変わるかみるためにつくったもの

マイグレーション用の資料

JUnit 5 User Guide

Release JUnit 5.0.0 · junit-team/junit5 · GitHub

>> JUnit 5.0.0 = Platform 1.0.0 + Jupiter 5.0.0 + Vintage 4.12.0

今までと違ってテスト実行エンジンとテスト用の記法が別れてると考えるといいかも(まだちゃんと理解できてません)
VintageはJUnit4との互換性を残すためのものらしい

置き換え方

ざっくり以下の用に置き換えると無事移行できました

名前 4 5
Before org.junit.Before org.junit.jupiter.api.BeforeEach
After org.junit.After org.junit.jupiter.api.AfterEach
Test org.junit.Test org.junit.jupiter.api.Test
assertEquals org.junit.Assert.assertEquals org.junit.jupiter.api.Assertions.assertEquals

ざっくりした例ですがこんな感じになります。
github.com

まとめ

変更点は大きいし、ライブラリにもたくさん文章が増えていますが、テストが少ないせいかマイグレーションするのは
ドキュメントを調べる時間もいれて30分位ですみました。
個人的にはBefore -> BeforeEachに名前が変わったことでいつ実行されるかわかりやすくなったと思います。
みなさんのマイグレーションの一助になるといいなーと思っています。

JUnit5の実装をすすめた皆さん本当にありがとうございました。