pep 526 and 周辺ツールについて
2017/01/31 Python 3.6 Release Party @Yahoo!Japan
自己紹介
@Masahito
github: masahitojp
株式会社ヌーラボ所属
主に Scala(be er Java) とJSと少々のPythonでご飯を食べています
近頃はmypyとGrumPyがお気に入り
今日話すこと
PEP 526 - Syntax for Variable Annotations
typing module
周辺ツール、特にmypy
PEP 526‐ Syntax for Variable
Annota ons
PEP 526はPEP484 の拡張です。
PEP 484 ‐ Type Hint ご存知のかた?
PEP 484について
PEP-484 Type Hint(en)
@t2y さんの日本語訳も提供されてます
PEP-484 Type Hint(ja)
PEP484について軽く説明
PEP 3107 Function Annotations ってのがPythonに入ってPythonの関
数に、任意のメタデータを追加するための構文を導入する
def compile(source: "something compilable",
filename: "where the compilable thing comes from",
mode: "is this a single statement or a suite?"):
PEP3107 では特に意味づけがなかったものを Type Hint として使おうっ
ていうのがPEP484です
def greeting(name: str) -> str:
return 'Hello ' + name
PEP484の目的としないもの
Python は依然として動的型付け言語のままです。 Python の作者たちは
(たとえ規約としてであっても)型ヒントを必須とすることを望んではいませ
ん。
この方針はPEP526でも同じです。
じゃーなにが追加になったの?
変数に対して型付けする構文が追加になった
from typing import List
# pep 484
a = [1,2,3] # type: List[int]
# We should add *comments*
path = None # type: Optional[str] # Path to module source
# pep 526
a: List[int] = [1,2,3]
path: Optional[str] = None # Path to module sourde
値を指定しなくてもよい
# pep 484
child # type: bool # これはゆるされない
# pep 526
child: bool # こちらはok
if age < 18:
child = True
else:
child = False
これは全部同じ意味になる
# 3.6でもpep484スタイルを許す(後方互換性!
hour = 24 # type: int
# 値を指定せずに定義して代入
hour: int; hour = 24
hour: int = 24
variable annota on はどこに格納される?
__annotaitons__ に格納される
>>> answer:int = 42
>>> __annotations__
{'answer': <class 'int'>}
クラス変数のみ格納される、インスタンス変数は無視される
>>> class Car:
... stats: ClassVar[Dict[str, int]] = {}
... def __init__(self) -> None:
... self.seats = 4
>>> c: Car = Car()
>>> c.__annotations__
{'stats': typing.ClassVar[typing.Dict[str, int]]}
# only ClassVar!
こんな書き方をしてもPythonとしてはゆるしてくれる
>>> alice: 'well done' = 'A+' #
>>> bob: 'what a shame' = 'F-'
>>> __annotations__
{'alice': 'well done', 'bob': 'what a shame'}
けどPEP526ではType Hintとしてつかうことを推奨する
typing
typing moduleとは
Python 3.5でPEP484が実装された時に入ったモジュール
DictとかTupleとかListみたいなbuild inのものはすでにこのモジュー
ルで定義されている
from typing import Dict, Tuple, List
ConnectionOptions : Dict[str, str]
Address : Tuple[str, int]
Server : Tuple[Address, ConnectionOptions]
もちろんドキュメントも https://docs.python.org/3/library/typing.html
pip install typing python2でもつかえる, mypyのpy2modeを使うとき
に実は使います
typing moduleの変更点
Collection
ContextManager
withで実行されるような型
class Context(object):
def __init__(self):
print '__init__()'
def __enter__(self):
print '__enter__()'
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print '__exit__()'
NamedTuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(x=1, y=2)
print(p.z) # Error: Point has no attribute 'z'
Python 3.6 で以下のようにかけるようになった
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
周辺ツール
周辺ツール
静的型チェッカー
っていうと難しく感じるかもですが要はコマンドです
mypy
pytype
IDE
PyCharm(今回は割愛
pytype
googleのリポジトリで開発されてる
Matthias Kramm(さんが一人でやってるっぽい
https://github.com/google/pytype
いまはPython2.7でのみ動く
けど、3.4/3.5モードで動かして型チェックすることも可能
pytype -V 3.5 program.py
PEP526のチェックもmasterブランチでは実装されてるが、いまのところ
3.6モードはない
Magic Exceptionがでる
mypy
pythonのレポジトリで開発されている
https://github.com/python/mypy
JukkaLさんが中心になって作成
今回は静的型チェッカーとしてのmypyについて話します
最近パッケージ名が変わった  mypy-lang -> mypy
こちらはすでに3.6モードが実装済み
じつはcobertruaで吐き出すモードがあったりとCIにつっこむと嬉しいオプ
ションもあります
mypy
from typing import Dict, NamedTuple
class Car:
stats: Dict[str, int] = {}
def __init__(self) -> None:
self.seats = 4
class Employee(NamedTuple):
name: str
id: int
c: Car = Car()
# print(c.__annotations__)
employee = Employee(name='Guido', id='x')
mypy --fast-parser --python-version 3.6 example.py
example.py:16: error: Argument 2 to "Employee" has incompatible type "str"; expected
typeshed について軽く
TypeScriptでいうところのDe nitely TypedのPython版
mypy/pytypeはこれを利用しています
つまりこれに対応していないモジュールは実行するとエラーになります
現状
(py36-mypy)~/s/p/try-pep526> cat collection.py
from typing import Collection
a: Collection[int] = [3,2,1]
a.append(1)
(py36-mypy)~/s/p/try-pep526> mypy --fast-parser --python-version 3.6 collection.
collection.py:2: error: Module 'typing' has no attribute 'Collection'
typeshedとtypingモジュールの状況
typeshedのtypingモジュールは3.5までしか対応してません  orz
そのため, いかのモジュールをimportすると定義されてないよエラーが
typing.ClassVar -> PEP526に書かれてるんだけどなぁ。。。。
https://github.com/python/typeshed/pull/889 無事近頃t
typeshedにはとりこまれた模様
typing.Collection -> Listとかで代用
typing.CotextManager -> ...
一応自分で定義(.ipr)をつくると行けそう
mypy for Python 3.6
構文追加系は動くのでぜひ使ってみるといいのでは
http://mypy.readthedocs.io/en/latest/python36.html
動く
PEP526対応済み(ただしClassVarはまだ
Underscores in numeric literals (PEP 515) e.g. million = 1_000_000
NamedTuple
未実装
Asynchronous generators (PEP 525)
Asynchronous comprehensions (PEP 530)
mypy for Python3.6
typeshedが対応すれば動くはず
typingで追加されたもの
時間が余ったとき用
typingにはじつは _Protocol ってのが存在してる
Protocols (a.k.a. structural subtyping)
要はこんな感じであるメソッドが実装されている型を新しくつくれるといい
ねっていう提案、mypy作者とGuido(!)を中心に議論
class Sized(Protocol):
@abstractmethod
def __len__(self) -> int: pass # __len__は特殊メソッド
def hoge(l : Sized) -> int:
return len(l) + 1
PEP 526が入ったことでこういうのもProtocolっぽく動くよねっていう議論が
class Point(<some magical base class):
x: float
y: float
z: float = 0
class MyPoint: # unrelated to Point
def __init__(self, x: float, y: float):
self.x, self.y = x, y
p = MyPoint(1, 2)
とこんな感じでまだ固まってないので typing.Protocol が使えるのはまだ先
のようです。
(typingの内部では使われているので興味ある方は読んでみるとよいかと)
まとめ
PEP526で変数名にType Hintつけるのが楽になった
typingモジュールもだんだん進歩している
ぜひ mypy とかを使っていただいて、  みんなで typeshed を育てていきま
しょう

20170131 python3 6 PEP526