Python と
型チェッカー
2018-05-19 Tetsuya Morimoto
自己紹介
●
森本 哲也
– twitter: @t2y
●
ポータルサイトの会社
– オブジェクトストレージの開発・運用
●
業務では Go 言語で開発
– 普段使いのツールやプロトタイピングに Python
●
エキスパート Python プログラミング改訂2版
– Python 3.5 ( 翻訳は 3.6) を対象
最近のニュース
●
Pyre: Fast Type Checking for Python
– 概要から引用
Facebook 社も Instagram 社も大規模に Python を使っています。私たちは Python の表現力、
柔軟性、開発における生産性をとても好んでいます。しかし、数百万行といった大規模コード
ベースの保守を考えると、そういった良いところにも陰りがみえてきます。
●
静的な保証がないと、既存のコードベースを安全に変更することが難しくなり、コードのエラーが発生しや
すくなって静的型付けされたコードと比べて開発が遅くなる
●
コード検索、コード補完、ナビゲーション、リファクタリングサポートなどの高品質なツールを構築するこ
とが難しい。こういったツールがないと、大規模コードベースで作業するときに特に弊害となる
これらの問題に対処するために、私たちは高速な PEP 484 互換の型チェッカーと深い静的解析
ツールを構築するための優れたプラットフォームの双方を兼ね備えた Pyre を構築しました。
型ヒント付きコードのサンプル
import json
import sys
from pprint import pformat
from typing import Any, Dict
def pretty_format(data: Dict[str, Any]) -> str:
return pformat(data, width=1)
def main(raw_data: str) -> None:
data = pretty_format(json.loads(raw_data))
data.append('mypy') # error: "str" has no attribute "append"
if __name__ == '__main__':
raw_data: str = sys.argv[1]
main(raw_data)
背景
5
これまでの経緯
●
Python 3.5 リリース
– PEP 484 型ヒント→ typing モジュールを提供
– mypy-lang 0.2.0 (2015-04-06)
●
Python 3.6 リリース
– PEP 526 変数アノテーション
– mypy 0.470 (2017-01-13)
●
いま
– mypy 0.600 (2018-05-02)
●
Python 3.7 予定
2015-09-13
2016-12-23
2018-06-15
この資料で
扱う範囲
最近の mypy のリリース履歴
●
0.600: mypy daemon
●
0.590: 型情報のパッケージングを試験導入 (PEP561)
●
...
●
0.530: structural subtyping を試験導入 (PEP544)
●
0.510: ClassVar サポート
●
...
●
0.470: pypi のパッケージ名を mypy-lang から mypy へ移行
●
(mypy-lang) 0.4 2017-01-13
2018-05-02
2017-10-06
2018-04-13
Python の開発スケジュールと並行して mypy に機能を試験導入している
Python への機能追加の流れ
1. サードパーティでやってみよ
mypy の開発は 2012 年開始 (Python3.2/3.3)
2. 標準ライブラリに入れましょう
型ヒントは typing モジュールとして提供 (Python3.5)
3. C 言語拡張でなんとかしましょう
typed_ast: 型コメントを扱える / 高速 ast ライブラリ
4. 言語に変更を加えましょう (Python3.6/3.7 PEP 526/560)
Python のコア機能の拡張は保守的に進められる
新規の機能がいきなり言語のコアに入ることは基本的にない
イマココ!
typing/mypy
最近の機能
9
mypy daemon
●
mypy 0.600 でサポート
– まだ beta レベル
●
数ファイル変更したときに毎回 mypy を実行す
るのはパフォーマンスがよくない
●
dmypy を使うと大規模なコードベースでは
mypy コマンドと比べて数十倍速いらしい
mypy command
$ time mypy --no-incremental sphinx
real 0m21.968s
user 0m20.986s
sys 0m0.769s
$ time mypy --follow-imports=error sphinx
sphinx/events.py: note: In member "disconnect" of class "EventManager":
sphinx/events.py:71:5: error: Missing return statement
real 0m16.784s
user 0m16.366s
sys 0m0.361s
mypy daemon
$ dmypy start -- --follow-imports=error
Daemon started
$ ps ax|grep dmypy
59452 ?? S 0:00.00 path/to/dmypy start -- --follow-imports=error
$ time dmypy check sphinx
real 0m20.714s
user 0m0.116s
sys 0m0.035s
$ time dmypy check sphinx
Daemon crashed!
Traceback (most recent call last):
...
AttributeError: 'NoneType' object has no attribute 'type_vars'
エラーになって計測できなかった。。。
TypedDict(1)
●
mypy_extensions の拡張機能
– 試験的機能だが、 mypy 0.530 から公式サポート
●
厳密なディクショナリの型定義
– 特定の key のみに限定したいとき
– value の型が複数あるようなとき
– すべての要素を指定させたいとき
TypedDict(2)
from typing import Dict, Any, Union
blade_runner: Dict[str, Any] = {'name': 'Blade Runner', 'year': 1982}
toy_story: Dict[str, Union[str, int]] = {'name': 'Toy Story', 'year': 1995}
from mypy_extensions import TypedDict
Movie = TypedDict('Movie', {'name': str, 'year': int})
blade_runner: Movie = {'name': 'Blade Runner', 'year': 1982}
toy_story = Movie(name='Toy Story', year=1995)
Movie はコンストラクタとしても使える
TypedDict を関数の引数に渡したときは型アノテーションはか
書かなくても mypy が型推論する
TypedDict(3)
name, year が定義されていないと型チェックでエラーになる
total=False を渡すとエラーにならない
the_rock = Movie(name='The Rock')
# error: Key 'year' missing for TypedDict "Movie"
Movie = TypedDict('Movie', {'name': str, 'year': int}, total=False)
the_rock = Movie(name='The Rock')
TypedDict(4)
3.6 からクラス構文でも定義できる
クラスだと型定義を継承することもできる
from mypy_extensions import TypedDict
class Movie(TypedDict):
name: str
year: int
blade_runner: Movie = {'name': 'Blade Runner', 'year': 1982}
class ExtraMovie(Movie):
director: str
the_rock = ExtraMovie(name='The Rock', year=1996, director='Michael Bay')
NamedTuple(1)
●
TypedDict 同様に 3.6 からクラス構文をつかっ
た NamedTuple の定義ができる
NamedTuple(2)
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(x=1, y=2)
print(p.z) # Error: Point has no attribute 'z'
from typing import NamedTuple
Point = NamedTuple('Point', [('x', int), ('y', int)])
p = Point(x=1, y='x')
# Error: Argument has incompatible type "str"; expected "int"
NamedTuple(3)
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(x=1, y='x')
# Error: Argument has incompatible type "str"; expected "int"
3.6 からクラス構文でも定義できる
NamedTuple の型定義は継承できない
NewType(1)
●
typing に 3.5.2 で追加
●
論理的なエラーチェックのためにクラスを生成
すると実行時オーバーヘッドになる
●
クラスを生成せずに型チェックできるヘルパー
関数を提供
NewType(2)
class UserId(int):
pass
def name_by_id(user_id: UserId) -> str:
...
from typing import NewType
UserId = NewType('UserId', int)
UserId('user')
# error: Argument 1 to "UserId" has incompatible type "str"; expected "int"
name_by_id(42)
# error: Argument 1 to "name_by_id" has incompatible type "int"; expected "UserId"
name_by_id(UserId(42)) # OK
num = UserId(5) + 1 # type: int
NewType の実装
def NewType(name, tp):
"""NewType creates simple unique types with almost zero
runtime overhead. NewType(name, tp) is considered a subtype of tp
by static type checkers. At runtime, NewType(name, tp) returns
a dummy function that simply returns its argument. Usage::
"""
def new_type(x):
return x
new_type.__name__ = name
new_type.__supertype__ = tp
return new_type
ソースファイルのオーバーロード
●
当初 PEP 484 では @overload デコレーターは
スタブファイルのみでのサポートと記述されて
いたが、その制約は見直された
– Relax constraints on @overload. It may occur in
modules if followed by a non-@overload version.
●
ソースコードにも記述して mypy で型チェック
できるようになった
●
Union 型では厳密に定義できないときがある
●
mypy 0.510 でサポート
リストの添字アクセス (Union)
from typing import Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
if isinstance(index, int):
... # Return a T here
elif isinstance(index, slice):
... # Return a sequence of Ts here
else:
raise TypeError(...)
リストの添字アクセス
- インデックス値かスライスを指定したら T か Sequence[T] を返す
リストの添字アクセス (overload)
リストの添字アクセス
- インデックス値を指定したら T を返す
- スライスを指定したら Sequence[T] を返す
from typing import overload, Sequence, TypeVar, Union
T = TypeVar('T')
class MyList(Sequence[T]):
@overload
def __getitem__(self, index: int) -> T:
pass # Don't put code here
@overload
def __getitem__(self, index: slice) -> Sequence[T]:
pass # Don't put code here
ジェネリック関数を返す関数
●
典型的な用途としてはデコレーター関数
●
mypy 0.510 でサポート
デコレート関数の型チェック
from typing import TypeVar, Callable, Any, cast
T = TypeVar('T', bound=Callable[..., Any])
def logged(description: str) -> Callable[[T], T]:
def decorator(f: T) -> T:
def wrapper(*args, **kwargs):
print('entering:', description)
value = f(*args, **kwargs)
print('leaving:', description)
return cast(T, wrapper)
return decorator
@logged('system initialization')
def init() -> None:
print('do something')
init(1) # error: Too many arguments (signature is correctly preserved)
Metaclass
●
シンプルな metaclass の型チェク
●
mypy0.501 でサポート
class Meta(type):
def __add__(self, x: str) -> str:
return 'a' + x
class C(metaclass=Meta):
...
print(C + 'x') # Okay
print(C + 1) # error: Unsupported operand types for + ("Type[C]" and "int")
循環インポート対策
●
型アノテーションを書くためにユーザー定義型
をインポートしていくうちに循環インポートが
発生しやすい
– mypy も循環インポートをうまく扱えなかった
●
mypy0.501 で対応
– 実行時にも影響を与えないやりかた
from typing import List, TYPE_CHECKING
if TYPE_CHECKING:
import bar
型ヒントと
関連 PEP
30
型ヒント関連の PEP の履歴
●
PEP 484 型ヒント
– Nominal Subtyping の型チェックのみ
●
PEP 526 変数アノテーションの構文
– Structural Subtyping に必要
●
Python 3.7
– PEP 560 typing モジュールとジェネリック型のコアサポート
– PEP 563 アノテーションの評価の延期
– PEP 544 プロトコル : Structural Subtyping
– PEP 561 型情報のパッケージング
Python 3.5
Python 3.6
( 承認 )
( 承認 )
延期
延期
mypy
support
PEP 560 typing モジュールと
ジェネリック型のコアサポート
●
typing モジュールのジェネリック型の様々な問題
– 実行時オーバーヘッド
– メタクラスの競合
– メタクラスハックによるバグの温床
●
2 つの特殊メソッドを追加
– __class_getitem__: クラスの添字のときに呼ばれる
– __mro_entries__: クラス定義の親リストにクラスオブ
ジェクトではないものが指定されたときに呼ばれる
クラスの添字を扱うメタクラス
class MetaSubscript(type):
def __new__(cls, name, bases, namespace, **kwds):
return super().__new__(cls, name, bases, dict(namespace))
def __getitem__(cls, params):
cls.params = params
return cls.__class__(cls.__name__, cls.__bases__, cls.__dict__)
class MyGeneric(metaclass=MetaSubscript):
pass
g = MyGeneric[str]()
print(MyGeneric.params) # <class 'str'>
クラスの作成時に metaclass.__new__ が呼ばれる
例えば、型アノテーションのためにクラスを
インポートしたときにオーバーヘッドになってしまう
PEP 563 アノテーションの評価の先送り
●
関数定義時点でアノテーションが評価されること
による問題
– 前方参照ができない
– インポート時に型ヒントが実行される
●
アノテーションを評価しないオプション
– Python 4.0 からデフォルトになる
from __future__ import annotations
前方参照のコード例
class A:
def f(self):
return B()
b = B() # NameError: name 'B' is not defined
def f():
b = B()
f() # NameError: name 'B' is not defined
a = A()
a.f() # NameError: name 'B' is not defined
class B:
pass
前方参照の型アノテーション
( 型アノテーションのみサポート )
from __future__ import annotations
class C:
field = 'c_field'
def method(self) -> C.field:... # this is OK
def method(self) -> field:... # this is OK
def method(self) -> C.D:... # this is OK
def method(self) -> D:... # this is OK
class D:
field2 = 'd_field'
def method(self) -> C.D.field2:... # this is OK
def method(self) -> D.field2:... # this is OK
def method(self) -> field2:... # this is OK
def method(self) -> field:... # this FAILS, class D doesn't
# see C's attributes, This was
# already true before this PEP.
PEP 544 プロトコル :
Structural Subtyping
●
別名 : 静的なダックタイピング
●
型ヒントの大きなマイルストーン?
●
https://github.com/python/typing/issues/11
– 作成日 :2014-10-16 (3.5 のリリース前 )
– 型ヒントが導入される以前から議論されていた
– 3.7 で提案されたが、残念ながら延期された
●
Python プログラマーにとって、より自然なセマ
ンティクスで型アノテーションを書ける
37
ダックタイピング
●
型の安全性における duck test を満たすアプリ
ケーションをダックタイピングと呼ぶ
– duck test とは、論理的推論方法 ( 帰納法 ) の一種
– " もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである "
●
型チェックを実行時に遅延させる
– 動的型付けやリフレクションを用いて実装される
●
ダックタイピングは
オブジェクトのメソッドや
プロパティの有無で決定される
def talk(x, y):
x.greet(y.name)
2 つのクラスが型として互換か
●
Nominal Subtyping ( 名前的部分型 )
– クラスを定義してクラス階層で部分型が成立する
– 継承によって実現する
●
Structural Subtyping ( 構造的部分型 )
– すべての属性 ( プロパティ ) とメソッドをもっている
なら部分型が成立する
– mypy は Protocol クラスを介してサポートする
from typing_extensions import Protocol
ダックタイピングと似ている!
Nominal Subtyping ( 名前的部分型 )
from typing import Sized, Iterable, Iterator
class Bucket(Sized, Iterable[int]):
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int:
len(items)
result: int = collect(Bucket()) # Passes type check
Structural Subtyping ( 構造的部分型 )
from typing import Iterator, Iterable
class Bucket:
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int:
len(items)
result: int = collect(Bucket()) # Passes type check
抽象基底クラス (ABC)
from abc import ABCMeta, abstractmethod
class InterfaceGreet(metaclass=ABCMeta):
@property
@abstractmethod
def name(self): ...
@abstractmethod
def greet(self, other): ...
class Person(InterfaceGreet):
name = ''
p = Person() # error: Cannot instantiate abstract class
# 'Person' with abstract attribute 'greet'
これまでのやり方
Python でインターフェースっぽいもの
ユーザー定義プロトコル (1)
from typing_extensions import Protocol
class Greetable(Protocol):
name: str
def greet(self, other: str) -> None: ...
class Person:
def __init__(self, name: str) -> None:
self.name = name
p: Greetable = Person(' もりもと ')
# error: Incompatible types in assignment
# (expression has type "Person", variable has type "Greetable")
# note: 'Person' is missing following 'Greetable' protocol member:
# note: greet
Greetable を継承しなくて良い!
ユーザー定義プロトコル (1)
from typing_extensions import Protocol
class Greetable(Protocol):
name: str
def greet(self, other: str) -> None: ...
class Person:
def __init__(self, name: str) -> None:
self.name = name
def greet(self, other: str) -> None:
print(' こんにちはー {}'.format(other))
class Cat:
def __init__(self, name: str) -> None:
self.name = name
def greet(self, other: str) -> None:
print(' にゃあー {}'.format(other))
def greet_each_other(x: Greetable, y: Greetable) -> None:
x.greet(y.name)
y.greet(x.name)
def main() -> None:
morimoto = Person(' もりもと ')
tama = Cat(' たま ')
greet_each_other(morimoto, tama)
ユーザー定義プロトコル (2)
class Anonymous:
def greet(self, other: str) -> None:
print(' やあ {}'.format(other))
def greet_each_other(x: Greetable, y: Greetable) -> None:
x.greet(y.name)
y.greet(x.name)
def main() -> None:
morimoto = Person(' もりもと ')
anonymous = Anonymous()
greet_each_other(morimoto, anonymous)
# error: Argument 2 to "greet_each_other" has incompatible type "Anonymous"; expected "Greetable"
# note: 'Anonymous' is missing following 'Greetable' protocol member:
# note: name
エラーメッセージもわかりやすい
PEP 561 型情報のパッケージング
●
mypy は mypy を実行する python インタープリ
ター向けにインストールされたパッケージディレ
クトリから型情報を含むパッケージを探索する
– 複数の仮想環境を扱うときなどうまくいかない
●
型情報を配布するパッケージングの仕組み
1.コード内に型アノテーションを記述している
2.実行コードと一緒に型情報の stub を提供する
3.型情報の stub を独立したパッケージで提供する
コード内に型アノテーションを記述
setup.py
package_a/
__init__.py
lib.py
py.typed
from distutils.core import setup
setup(
name="SuperPackageA",
author="Me",
version="0.1",
package_data={"package_a": ["py.typed"]},
packages=["package_a"]
)
py.typed を作る
実行コードと一緒に
型情報の stub を提供する
setup.py
package_b/
__init__.py
lib.py
lib.pyi
py.typed
from distutils.core import setup
setup(
name="SuperPackageB",
author="Me",
version="0.1",
package_data={"package_b": ["py.typed", "lib.pyi"]},
packages=["package_b"]
)
py.typed と lib.pyi を作る
型情報の stub を独立した
パッケージで提供する
setup.py
package_c-stubs/
__init__.pyi
lib.pyi
from distutils.core import setup
setup(
name="SuperPackageC",
author="Me",
version="0.1",
package_data={
"package_c-stubs": ["__init__.pyi", "lib.pyi"]
},
packages=["package_c-stubs"]
)
__init__.pyi と lib.pyi を作る
業務で型チェックを試している知人から
●
いま型アノテーションをつけようとしたときに
遭遇する課題
– サードパーティで型アノテーションがついていな
い、もしくはスタブが提供されていない
– 社内リポジトリにスタブファイルを作ったりしている
●
ローカルで CI 用途に使うとしても型情報のパッ
ケージングすごく大事
mypy と
関連プロジェクト
51
mypy プロジェクト (1)
●
http://mypy-lang.org/
●
Python 本体は型ヒントの構文のみを標準化
– 標準ライブラリとして typing モジュールを提供
●
型チェッカーはサードパーティ
– mypy は型チェッカーの参照実装のようなもの
– https://github.com/python/mypy
●
リポジトリは python organization 配下にある
●
コミュニケーション (ML ではなく Gitter)
– https://gitter.im/python/typing
mypy プロジェクト (2)
●
コア開発者
– Jukka Lehtosalo: mypy 作者 (@Dropbox)
– Guido van Rossum: python 作者 (@Dropbox)
– David Fisher: (@Dropbox)
– Ivan Levkivskyi: 理論物理学 (@University of Bern)
– Elazar Gershuni: (@Technion)
– Michael J. Sullivan: (@Dropbox)
●
直近でコントリビュートしている上位開発者
Dropbox 社が強い関心をもっているのがわかる
mypy プロジェクト (3)
●
mypy_extensions
– https://pypi.org/project/mypy_extensions/
●
コードは mypy リポジトリの内部にある
– https://github.com/python/mypy/tree/master/exte
nsions
●
mypy の試験的な機能や拡張を提供
– TypedDict( 後述 ) を使うときに必要
●
Mypy 0.530 Released
typing プロジェクト (1)
●
https://github.com/python/typing
– typing モジュールの開発や議論
– 当初の予定では 3.5.0 から 3.7.0 までだった?
●
3.7.0 で typing モジュールの“ provisional" を外す予定
– https://github.com/python/typing/issues/495#i
ssuecomment-342644111
●
typing を標準ライブラリから外すかどうかの議論
●
少なくとも 3.7.0 では“ provisional" にしよう
typing プロジェクト (2)
●
コア開発者
– Guido van Rossum: python 作者 (@Dropbox)
– Ivan Levkivskyi: 理論物理学 (@University of Bern)
– Łukasz Langa: (@Facebook)
– Andrey Vlasovskikh: (@JetBrains)
– Jukka Lehtosalo: mypy 作者 (@Dropbox)
●
コントリビュートの上位 5 人
mypy/typing ともに Guido 氏がイニシアティブをもって取り組んでいる
typing プロジェクト (3)
●
typing_extensions
– https://pypi.org/project/typing-extensions/
●
コードは typing リポジトリの内部にある
– https://github.com/python/typing/tree/master/ty
ping_extensions
●
typing の試験的な機能や型を提供
●
旧バージョン (3.5/3.6) のバックポートとしても
使える
Protocol は typing_extensions からインポートできる
typeshed リポジトリ
●
https://github.com/python/typeshed
– 型チェックのための stub 共有リポジトリ
– TypeScript でいうところの DefinitelyTyped
●
標準ライブラリの stub を提供
●
サードパーティはまだ少し
– 追加するには対象ライブラリのメンテナーに連絡し
て許可を得る
typed_ast プロジェクト
●
https://github.com/python/typed_ast
– mypy の依存パッケージとしてインストールされる
– Python2.7/3 向けのパーサーを提供する
– 標準 ast ライブラリと完全互換
●
型コメントを扱える
●
標準 ast のバグは直さない (upstream で修正しない限り )
– 標準 ast よりも高速らしい
その他の
ツール
60
Cython と型アノテーション
●
Pure Python Mode
– Python 文法の範囲内でコードを記述
– 最適化したいところだけでコレータを付与
– 型ヒントの構文で Cython の型情報を記述
from ctypes import c_char, POINTER
# Before
def feeder(c_string):
cdef char* c_string = NULL
# After
def feeder(c_string: POINTER(c_char)) -> None:
pass
型アノテーションの自動生成
●
PyAnnotate (@Dropbox)
– https://github.com/dropbox/pyannotate
– Python2/3 向け、型コメントを生成
●
MonkeyType (@Instagram)
– https://github.com/Instagram/MonkeyType
– Python3 向け、 stub/ 型アノテーションを生成
●
リファレンス
– Python の型アノテーションを自動生成する
●
PyAnnnotate と MonkeyType の調べてみた
その他の型チェッカー
●
PyCharm: Type Hinting in PyCharm
– PEP 563 アノテーションの評価の延期
– 型ヒントや変数アノテーションのサポート
– Typeshed との連携
●
Pyre: https://pyre-check.org/
– 高速でスケーラブルな型チェッカー
まとめ
64
型ヒントの成功の兆し?
●
typing/mypy の開発は十分に活発にみえる
– パフォーマンスについて懸念されるようになった
– 型ヒント関連の PEP も継続的に提案されている
●
大規模なコードベースをもつ企業での運用
– Dropbox/Zulip
●
ノウハウやツールを公開
●
Guido, Jukka 氏も活発に開発
– Facebook/Instagram
●
エディタや CI 連携を考慮した
実務的な型チェッカーやライブラリを公開
今後の実運用からの
フィードバックも
期待される
typing は 3.8 で stable ?
●
3.5 で型ヒントを導入したとき
– 賛否両論で議論が盛り上がった
– 3.7 で provisional→stable の予定だったが延期
– それでも開発は活発にみえる
●
3.8 の期待
– Structural Subtyping がサポートされるはず
– mypy は先行サポートしているので待つ必要はない
今後のサードパーティの対応?
●
typeshed にはまだまだ少ない
– スタブのメンテはしんどいよね
●
よく使われているサードパーティがどのぐらい
対応していくか
– 2020 年の Python2 のサポート終了
– 2/3 対応から 3 のコードベースへ移行?
●
型アノテーションの自動生成の未来
– いまツールが公開されたところ
リファレンス
68
Python 開発
●
Python ドキュメント
– What’s New In Python 3.7
– typing — 型ヒントのサポート
●
DSAS 開発者の部屋
– 最近のPython-dev(2017-12)
– 最近のPython-dev(2017-06)
– 最近のPython-dev (2017-05)
●
言語設計者たちが考えること O'Reilly Japan, Inc.
型ヒント
●
What is Gradual Typing: 漸進的型付けとは何か
●
PEP
– [翻訳] PEP 0484 -- 型ヒント (Type Hints)
●
Python と型ヒント (Type Hints) と #pyconjp
– PEP 526 -- Syntax for Variable Annotations
– PEP 544 -- Protocols: Structural subtyping (static duck typing)
– PEP 560 -- Core support for typing module and generic types
– PEP 561 -- Distributing and Packaging Type Information
– PEP 563 -- Postponed Evaluation of Annotations
●
[翻訳] Python の静的型、すごい mypy!
型システム
●
https://en.wikipedia.org/wiki/Duck_typing
●
https://en.wikipedia.org/wiki/Structural_ty
pe_system
●
https://en.wikipedia.org/wiki/Subtyping
●
第4回 関数型言語とオブジェクト指向,およびOC
amlの"O"について
その他のツール
●
Cython: Python Typing Proposal
●
Dropbox releases PyAnnotate -- auto-genera
te type annotations for mypy
●
Dropbox releases mypy-protobuf
●
Let your code type-hint itself: introducing
open source MonkeyType
●
Pycon2017 instagram keynote
●
スライド内のサンプルコード
– https://github.com/t2y/python-study/tree/mas
ter/MiniOsaka

Pythonと型チェッカー

  • 1.
  • 2.
    自己紹介 ● 森本 哲也 – twitter:@t2y ● ポータルサイトの会社 – オブジェクトストレージの開発・運用 ● 業務では Go 言語で開発 – 普段使いのツールやプロトタイピングに Python ● エキスパート Python プログラミング改訂2版 – Python 3.5 ( 翻訳は 3.6) を対象
  • 3.
    最近のニュース ● Pyre: Fast TypeChecking for Python – 概要から引用 Facebook 社も Instagram 社も大規模に Python を使っています。私たちは Python の表現力、 柔軟性、開発における生産性をとても好んでいます。しかし、数百万行といった大規模コード ベースの保守を考えると、そういった良いところにも陰りがみえてきます。 ● 静的な保証がないと、既存のコードベースを安全に変更することが難しくなり、コードのエラーが発生しや すくなって静的型付けされたコードと比べて開発が遅くなる ● コード検索、コード補完、ナビゲーション、リファクタリングサポートなどの高品質なツールを構築するこ とが難しい。こういったツールがないと、大規模コードベースで作業するときに特に弊害となる これらの問題に対処するために、私たちは高速な PEP 484 互換の型チェッカーと深い静的解析 ツールを構築するための優れたプラットフォームの双方を兼ね備えた Pyre を構築しました。
  • 4.
    型ヒント付きコードのサンプル import json import sys frompprint import pformat from typing import Any, Dict def pretty_format(data: Dict[str, Any]) -> str: return pformat(data, width=1) def main(raw_data: str) -> None: data = pretty_format(json.loads(raw_data)) data.append('mypy') # error: "str" has no attribute "append" if __name__ == '__main__': raw_data: str = sys.argv[1] main(raw_data)
  • 5.
  • 6.
    これまでの経緯 ● Python 3.5 リリース –PEP 484 型ヒント→ typing モジュールを提供 – mypy-lang 0.2.0 (2015-04-06) ● Python 3.6 リリース – PEP 526 変数アノテーション – mypy 0.470 (2017-01-13) ● いま – mypy 0.600 (2018-05-02) ● Python 3.7 予定 2015-09-13 2016-12-23 2018-06-15 この資料で 扱う範囲
  • 7.
    最近の mypy のリリース履歴 ● 0.600:mypy daemon ● 0.590: 型情報のパッケージングを試験導入 (PEP561) ● ... ● 0.530: structural subtyping を試験導入 (PEP544) ● 0.510: ClassVar サポート ● ... ● 0.470: pypi のパッケージ名を mypy-lang から mypy へ移行 ● (mypy-lang) 0.4 2017-01-13 2018-05-02 2017-10-06 2018-04-13 Python の開発スケジュールと並行して mypy に機能を試験導入している
  • 8.
    Python への機能追加の流れ 1. サードパーティでやってみよ mypyの開発は 2012 年開始 (Python3.2/3.3) 2. 標準ライブラリに入れましょう 型ヒントは typing モジュールとして提供 (Python3.5) 3. C 言語拡張でなんとかしましょう typed_ast: 型コメントを扱える / 高速 ast ライブラリ 4. 言語に変更を加えましょう (Python3.6/3.7 PEP 526/560) Python のコア機能の拡張は保守的に進められる 新規の機能がいきなり言語のコアに入ることは基本的にない イマココ!
  • 9.
  • 10.
    mypy daemon ● mypy 0.600でサポート – まだ beta レベル ● 数ファイル変更したときに毎回 mypy を実行す るのはパフォーマンスがよくない ● dmypy を使うと大規模なコードベースでは mypy コマンドと比べて数十倍速いらしい
  • 11.
    mypy command $ timemypy --no-incremental sphinx real 0m21.968s user 0m20.986s sys 0m0.769s $ time mypy --follow-imports=error sphinx sphinx/events.py: note: In member "disconnect" of class "EventManager": sphinx/events.py:71:5: error: Missing return statement real 0m16.784s user 0m16.366s sys 0m0.361s
  • 12.
    mypy daemon $ dmypystart -- --follow-imports=error Daemon started $ ps ax|grep dmypy 59452 ?? S 0:00.00 path/to/dmypy start -- --follow-imports=error $ time dmypy check sphinx real 0m20.714s user 0m0.116s sys 0m0.035s $ time dmypy check sphinx Daemon crashed! Traceback (most recent call last): ... AttributeError: 'NoneType' object has no attribute 'type_vars' エラーになって計測できなかった。。。
  • 13.
    TypedDict(1) ● mypy_extensions の拡張機能 – 試験的機能だが、mypy 0.530 から公式サポート ● 厳密なディクショナリの型定義 – 特定の key のみに限定したいとき – value の型が複数あるようなとき – すべての要素を指定させたいとき
  • 14.
    TypedDict(2) from typing importDict, Any, Union blade_runner: Dict[str, Any] = {'name': 'Blade Runner', 'year': 1982} toy_story: Dict[str, Union[str, int]] = {'name': 'Toy Story', 'year': 1995} from mypy_extensions import TypedDict Movie = TypedDict('Movie', {'name': str, 'year': int}) blade_runner: Movie = {'name': 'Blade Runner', 'year': 1982} toy_story = Movie(name='Toy Story', year=1995) Movie はコンストラクタとしても使える TypedDict を関数の引数に渡したときは型アノテーションはか 書かなくても mypy が型推論する
  • 15.
    TypedDict(3) name, year が定義されていないと型チェックでエラーになる total=Falseを渡すとエラーにならない the_rock = Movie(name='The Rock') # error: Key 'year' missing for TypedDict "Movie" Movie = TypedDict('Movie', {'name': str, 'year': int}, total=False) the_rock = Movie(name='The Rock')
  • 16.
    TypedDict(4) 3.6 からクラス構文でも定義できる クラスだと型定義を継承することもできる from mypy_extensionsimport TypedDict class Movie(TypedDict): name: str year: int blade_runner: Movie = {'name': 'Blade Runner', 'year': 1982} class ExtraMovie(Movie): director: str the_rock = ExtraMovie(name='The Rock', year=1996, director='Michael Bay')
  • 17.
    NamedTuple(1) ● TypedDict 同様に 3.6からクラス構文をつかっ た NamedTuple の定義ができる
  • 18.
    NamedTuple(2) from collections importnamedtuple Point = namedtuple('Point', ['x', 'y']) p = Point(x=1, y=2) print(p.z) # Error: Point has no attribute 'z' from typing import NamedTuple Point = NamedTuple('Point', [('x', int), ('y', int)]) p = Point(x=1, y='x') # Error: Argument has incompatible type "str"; expected "int"
  • 19.
    NamedTuple(3) from typing importNamedTuple class Point(NamedTuple): x: int y: int p = Point(x=1, y='x') # Error: Argument has incompatible type "str"; expected "int" 3.6 からクラス構文でも定義できる NamedTuple の型定義は継承できない
  • 20.
    NewType(1) ● typing に 3.5.2で追加 ● 論理的なエラーチェックのためにクラスを生成 すると実行時オーバーヘッドになる ● クラスを生成せずに型チェックできるヘルパー 関数を提供
  • 21.
    NewType(2) class UserId(int): pass def name_by_id(user_id:UserId) -> str: ... from typing import NewType UserId = NewType('UserId', int) UserId('user') # error: Argument 1 to "UserId" has incompatible type "str"; expected "int" name_by_id(42) # error: Argument 1 to "name_by_id" has incompatible type "int"; expected "UserId" name_by_id(UserId(42)) # OK num = UserId(5) + 1 # type: int
  • 22.
    NewType の実装 def NewType(name,tp): """NewType creates simple unique types with almost zero runtime overhead. NewType(name, tp) is considered a subtype of tp by static type checkers. At runtime, NewType(name, tp) returns a dummy function that simply returns its argument. Usage:: """ def new_type(x): return x new_type.__name__ = name new_type.__supertype__ = tp return new_type
  • 23.
    ソースファイルのオーバーロード ● 当初 PEP 484では @overload デコレーターは スタブファイルのみでのサポートと記述されて いたが、その制約は見直された – Relax constraints on @overload. It may occur in modules if followed by a non-@overload version. ● ソースコードにも記述して mypy で型チェック できるようになった ● Union 型では厳密に定義できないときがある ● mypy 0.510 でサポート
  • 24.
    リストの添字アクセス (Union) from typingimport Sequence, TypeVar, Union T = TypeVar('T') class MyList(Sequence[T]): def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]: if isinstance(index, int): ... # Return a T here elif isinstance(index, slice): ... # Return a sequence of Ts here else: raise TypeError(...) リストの添字アクセス - インデックス値かスライスを指定したら T か Sequence[T] を返す
  • 25.
    リストの添字アクセス (overload) リストの添字アクセス - インデックス値を指定したらT を返す - スライスを指定したら Sequence[T] を返す from typing import overload, Sequence, TypeVar, Union T = TypeVar('T') class MyList(Sequence[T]): @overload def __getitem__(self, index: int) -> T: pass # Don't put code here @overload def __getitem__(self, index: slice) -> Sequence[T]: pass # Don't put code here
  • 26.
  • 27.
    デコレート関数の型チェック from typing importTypeVar, Callable, Any, cast T = TypeVar('T', bound=Callable[..., Any]) def logged(description: str) -> Callable[[T], T]: def decorator(f: T) -> T: def wrapper(*args, **kwargs): print('entering:', description) value = f(*args, **kwargs) print('leaving:', description) return cast(T, wrapper) return decorator @logged('system initialization') def init() -> None: print('do something') init(1) # error: Too many arguments (signature is correctly preserved)
  • 28.
    Metaclass ● シンプルな metaclass の型チェク ● mypy0.501でサポート class Meta(type): def __add__(self, x: str) -> str: return 'a' + x class C(metaclass=Meta): ... print(C + 'x') # Okay print(C + 1) # error: Unsupported operand types for + ("Type[C]" and "int")
  • 29.
  • 30.
  • 31.
    型ヒント関連の PEP の履歴 ● PEP484 型ヒント – Nominal Subtyping の型チェックのみ ● PEP 526 変数アノテーションの構文 – Structural Subtyping に必要 ● Python 3.7 – PEP 560 typing モジュールとジェネリック型のコアサポート – PEP 563 アノテーションの評価の延期 – PEP 544 プロトコル : Structural Subtyping – PEP 561 型情報のパッケージング Python 3.5 Python 3.6 ( 承認 ) ( 承認 ) 延期 延期 mypy support
  • 32.
    PEP 560 typingモジュールと ジェネリック型のコアサポート ● typing モジュールのジェネリック型の様々な問題 – 実行時オーバーヘッド – メタクラスの競合 – メタクラスハックによるバグの温床 ● 2 つの特殊メソッドを追加 – __class_getitem__: クラスの添字のときに呼ばれる – __mro_entries__: クラス定義の親リストにクラスオブ ジェクトではないものが指定されたときに呼ばれる
  • 33.
    クラスの添字を扱うメタクラス class MetaSubscript(type): def __new__(cls,name, bases, namespace, **kwds): return super().__new__(cls, name, bases, dict(namespace)) def __getitem__(cls, params): cls.params = params return cls.__class__(cls.__name__, cls.__bases__, cls.__dict__) class MyGeneric(metaclass=MetaSubscript): pass g = MyGeneric[str]() print(MyGeneric.params) # <class 'str'> クラスの作成時に metaclass.__new__ が呼ばれる 例えば、型アノテーションのためにクラスを インポートしたときにオーバーヘッドになってしまう
  • 34.
    PEP 563 アノテーションの評価の先送り ● 関数定義時点でアノテーションが評価されること による問題 –前方参照ができない – インポート時に型ヒントが実行される ● アノテーションを評価しないオプション – Python 4.0 からデフォルトになる from __future__ import annotations
  • 35.
    前方参照のコード例 class A: def f(self): returnB() b = B() # NameError: name 'B' is not defined def f(): b = B() f() # NameError: name 'B' is not defined a = A() a.f() # NameError: name 'B' is not defined class B: pass
  • 36.
    前方参照の型アノテーション ( 型アノテーションのみサポート ) from__future__ import annotations class C: field = 'c_field' def method(self) -> C.field:... # this is OK def method(self) -> field:... # this is OK def method(self) -> C.D:... # this is OK def method(self) -> D:... # this is OK class D: field2 = 'd_field' def method(self) -> C.D.field2:... # this is OK def method(self) -> D.field2:... # this is OK def method(self) -> field2:... # this is OK def method(self) -> field:... # this FAILS, class D doesn't # see C's attributes, This was # already true before this PEP.
  • 37.
    PEP 544 プロトコル: Structural Subtyping ● 別名 : 静的なダックタイピング ● 型ヒントの大きなマイルストーン? ● https://github.com/python/typing/issues/11 – 作成日 :2014-10-16 (3.5 のリリース前 ) – 型ヒントが導入される以前から議論されていた – 3.7 で提案されたが、残念ながら延期された ● Python プログラマーにとって、より自然なセマ ンティクスで型アノテーションを書ける 37
  • 38.
    ダックタイピング ● 型の安全性における duck testを満たすアプリ ケーションをダックタイピングと呼ぶ – duck test とは、論理的推論方法 ( 帰納法 ) の一種 – " もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである " ● 型チェックを実行時に遅延させる – 動的型付けやリフレクションを用いて実装される ● ダックタイピングは オブジェクトのメソッドや プロパティの有無で決定される def talk(x, y): x.greet(y.name)
  • 39.
    2 つのクラスが型として互換か ● Nominal Subtyping( 名前的部分型 ) – クラスを定義してクラス階層で部分型が成立する – 継承によって実現する ● Structural Subtyping ( 構造的部分型 ) – すべての属性 ( プロパティ ) とメソッドをもっている なら部分型が成立する – mypy は Protocol クラスを介してサポートする from typing_extensions import Protocol ダックタイピングと似ている!
  • 40.
    Nominal Subtyping (名前的部分型 ) from typing import Sized, Iterable, Iterator class Bucket(Sized, Iterable[int]): def __len__(self) -> int: ... def __iter__(self) -> Iterator[int]: ... def collect(items: Iterable[int]) -> int: len(items) result: int = collect(Bucket()) # Passes type check
  • 41.
    Structural Subtyping (構造的部分型 ) from typing import Iterator, Iterable class Bucket: def __len__(self) -> int: ... def __iter__(self) -> Iterator[int]: ... def collect(items: Iterable[int]) -> int: len(items) result: int = collect(Bucket()) # Passes type check
  • 42.
    抽象基底クラス (ABC) from abcimport ABCMeta, abstractmethod class InterfaceGreet(metaclass=ABCMeta): @property @abstractmethod def name(self): ... @abstractmethod def greet(self, other): ... class Person(InterfaceGreet): name = '' p = Person() # error: Cannot instantiate abstract class # 'Person' with abstract attribute 'greet' これまでのやり方 Python でインターフェースっぽいもの
  • 43.
    ユーザー定義プロトコル (1) from typing_extensionsimport Protocol class Greetable(Protocol): name: str def greet(self, other: str) -> None: ... class Person: def __init__(self, name: str) -> None: self.name = name p: Greetable = Person(' もりもと ') # error: Incompatible types in assignment # (expression has type "Person", variable has type "Greetable") # note: 'Person' is missing following 'Greetable' protocol member: # note: greet Greetable を継承しなくて良い!
  • 44.
    ユーザー定義プロトコル (1) from typing_extensionsimport Protocol class Greetable(Protocol): name: str def greet(self, other: str) -> None: ... class Person: def __init__(self, name: str) -> None: self.name = name def greet(self, other: str) -> None: print(' こんにちはー {}'.format(other)) class Cat: def __init__(self, name: str) -> None: self.name = name def greet(self, other: str) -> None: print(' にゃあー {}'.format(other)) def greet_each_other(x: Greetable, y: Greetable) -> None: x.greet(y.name) y.greet(x.name) def main() -> None: morimoto = Person(' もりもと ') tama = Cat(' たま ') greet_each_other(morimoto, tama)
  • 45.
    ユーザー定義プロトコル (2) class Anonymous: defgreet(self, other: str) -> None: print(' やあ {}'.format(other)) def greet_each_other(x: Greetable, y: Greetable) -> None: x.greet(y.name) y.greet(x.name) def main() -> None: morimoto = Person(' もりもと ') anonymous = Anonymous() greet_each_other(morimoto, anonymous) # error: Argument 2 to "greet_each_other" has incompatible type "Anonymous"; expected "Greetable" # note: 'Anonymous' is missing following 'Greetable' protocol member: # note: name エラーメッセージもわかりやすい
  • 46.
    PEP 561 型情報のパッケージング ● mypyは mypy を実行する python インタープリ ター向けにインストールされたパッケージディレ クトリから型情報を含むパッケージを探索する – 複数の仮想環境を扱うときなどうまくいかない ● 型情報を配布するパッケージングの仕組み 1.コード内に型アノテーションを記述している 2.実行コードと一緒に型情報の stub を提供する 3.型情報の stub を独立したパッケージで提供する
  • 47.
    コード内に型アノテーションを記述 setup.py package_a/ __init__.py lib.py py.typed from distutils.core importsetup setup( name="SuperPackageA", author="Me", version="0.1", package_data={"package_a": ["py.typed"]}, packages=["package_a"] ) py.typed を作る
  • 48.
    実行コードと一緒に 型情報の stub を提供する setup.py package_b/ __init__.py lib.py lib.pyi py.typed fromdistutils.core import setup setup( name="SuperPackageB", author="Me", version="0.1", package_data={"package_b": ["py.typed", "lib.pyi"]}, packages=["package_b"] ) py.typed と lib.pyi を作る
  • 49.
    型情報の stub を独立した パッケージで提供する setup.py package_c-stubs/ __init__.pyi lib.pyi fromdistutils.core import setup setup( name="SuperPackageC", author="Me", version="0.1", package_data={ "package_c-stubs": ["__init__.pyi", "lib.pyi"] }, packages=["package_c-stubs"] ) __init__.pyi と lib.pyi を作る
  • 50.
  • 51.
  • 52.
    mypy プロジェクト (1) ● http://mypy-lang.org/ ● Python本体は型ヒントの構文のみを標準化 – 標準ライブラリとして typing モジュールを提供 ● 型チェッカーはサードパーティ – mypy は型チェッカーの参照実装のようなもの – https://github.com/python/mypy ● リポジトリは python organization 配下にある ● コミュニケーション (ML ではなく Gitter) – https://gitter.im/python/typing
  • 53.
    mypy プロジェクト (2) ● コア開発者 –Jukka Lehtosalo: mypy 作者 (@Dropbox) – Guido van Rossum: python 作者 (@Dropbox) – David Fisher: (@Dropbox) – Ivan Levkivskyi: 理論物理学 (@University of Bern) – Elazar Gershuni: (@Technion) – Michael J. Sullivan: (@Dropbox) ● 直近でコントリビュートしている上位開発者 Dropbox 社が強い関心をもっているのがわかる
  • 54.
    mypy プロジェクト (3) ● mypy_extensions –https://pypi.org/project/mypy_extensions/ ● コードは mypy リポジトリの内部にある – https://github.com/python/mypy/tree/master/exte nsions ● mypy の試験的な機能や拡張を提供 – TypedDict( 後述 ) を使うときに必要 ● Mypy 0.530 Released
  • 55.
    typing プロジェクト (1) ● https://github.com/python/typing –typing モジュールの開発や議論 – 当初の予定では 3.5.0 から 3.7.0 までだった? ● 3.7.0 で typing モジュールの“ provisional" を外す予定 – https://github.com/python/typing/issues/495#i ssuecomment-342644111 ● typing を標準ライブラリから外すかどうかの議論 ● 少なくとも 3.7.0 では“ provisional" にしよう
  • 56.
    typing プロジェクト (2) ● コア開発者 –Guido van Rossum: python 作者 (@Dropbox) – Ivan Levkivskyi: 理論物理学 (@University of Bern) – Łukasz Langa: (@Facebook) – Andrey Vlasovskikh: (@JetBrains) – Jukka Lehtosalo: mypy 作者 (@Dropbox) ● コントリビュートの上位 5 人 mypy/typing ともに Guido 氏がイニシアティブをもって取り組んでいる
  • 57.
    typing プロジェクト (3) ● typing_extensions –https://pypi.org/project/typing-extensions/ ● コードは typing リポジトリの内部にある – https://github.com/python/typing/tree/master/ty ping_extensions ● typing の試験的な機能や型を提供 ● 旧バージョン (3.5/3.6) のバックポートとしても 使える Protocol は typing_extensions からインポートできる
  • 58.
    typeshed リポジトリ ● https://github.com/python/typeshed – 型チェックのためのstub 共有リポジトリ – TypeScript でいうところの DefinitelyTyped ● 標準ライブラリの stub を提供 ● サードパーティはまだ少し – 追加するには対象ライブラリのメンテナーに連絡し て許可を得る
  • 59.
    typed_ast プロジェクト ● https://github.com/python/typed_ast – mypyの依存パッケージとしてインストールされる – Python2.7/3 向けのパーサーを提供する – 標準 ast ライブラリと完全互換 ● 型コメントを扱える ● 標準 ast のバグは直さない (upstream で修正しない限り ) – 標準 ast よりも高速らしい
  • 60.
  • 61.
    Cython と型アノテーション ● Pure PythonMode – Python 文法の範囲内でコードを記述 – 最適化したいところだけでコレータを付与 – 型ヒントの構文で Cython の型情報を記述 from ctypes import c_char, POINTER # Before def feeder(c_string): cdef char* c_string = NULL # After def feeder(c_string: POINTER(c_char)) -> None: pass
  • 62.
    型アノテーションの自動生成 ● PyAnnotate (@Dropbox) – https://github.com/dropbox/pyannotate –Python2/3 向け、型コメントを生成 ● MonkeyType (@Instagram) – https://github.com/Instagram/MonkeyType – Python3 向け、 stub/ 型アノテーションを生成 ● リファレンス – Python の型アノテーションを自動生成する ● PyAnnnotate と MonkeyType の調べてみた
  • 63.
    その他の型チェッカー ● PyCharm: Type Hintingin PyCharm – PEP 563 アノテーションの評価の延期 – 型ヒントや変数アノテーションのサポート – Typeshed との連携 ● Pyre: https://pyre-check.org/ – 高速でスケーラブルな型チェッカー
  • 64.
  • 65.
    型ヒントの成功の兆し? ● typing/mypy の開発は十分に活発にみえる – パフォーマンスについて懸念されるようになった –型ヒント関連の PEP も継続的に提案されている ● 大規模なコードベースをもつ企業での運用 – Dropbox/Zulip ● ノウハウやツールを公開 ● Guido, Jukka 氏も活発に開発 – Facebook/Instagram ● エディタや CI 連携を考慮した 実務的な型チェッカーやライブラリを公開 今後の実運用からの フィードバックも 期待される
  • 66.
    typing は 3.8で stable ? ● 3.5 で型ヒントを導入したとき – 賛否両論で議論が盛り上がった – 3.7 で provisional→stable の予定だったが延期 – それでも開発は活発にみえる ● 3.8 の期待 – Structural Subtyping がサポートされるはず – mypy は先行サポートしているので待つ必要はない
  • 67.
    今後のサードパーティの対応? ● typeshed にはまだまだ少ない – スタブのメンテはしんどいよね ● よく使われているサードパーティがどのぐらい 対応していくか –2020 年の Python2 のサポート終了 – 2/3 対応から 3 のコードベースへ移行? ● 型アノテーションの自動生成の未来 – いまツールが公開されたところ
  • 68.
  • 69.
    Python 開発 ● Python ドキュメント –What’s New In Python 3.7 – typing — 型ヒントのサポート ● DSAS 開発者の部屋 – 最近のPython-dev(2017-12) – 最近のPython-dev(2017-06) – 最近のPython-dev (2017-05) ● 言語設計者たちが考えること O'Reilly Japan, Inc.
  • 70.
    型ヒント ● What is GradualTyping: 漸進的型付けとは何か ● PEP – [翻訳] PEP 0484 -- 型ヒント (Type Hints) ● Python と型ヒント (Type Hints) と #pyconjp – PEP 526 -- Syntax for Variable Annotations – PEP 544 -- Protocols: Structural subtyping (static duck typing) – PEP 560 -- Core support for typing module and generic types – PEP 561 -- Distributing and Packaging Type Information – PEP 563 -- Postponed Evaluation of Annotations ● [翻訳] Python の静的型、すごい mypy!
  • 71.
  • 72.
    その他のツール ● Cython: Python TypingProposal ● Dropbox releases PyAnnotate -- auto-genera te type annotations for mypy ● Dropbox releases mypy-protobuf ● Let your code type-hint itself: introducing open source MonkeyType ● Pycon2017 instagram keynote ● スライド内のサンプルコード – https://github.com/t2y/python-study/tree/mas ter/MiniOsaka