Pythonと型チェッカー

Tetsuya Morimoto
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
1 of 72

Recommended

Python と型ヒント (Type Hints) by
Python と型ヒント (Type Hints)Python と型ヒント (Type Hints)
Python と型ヒント (Type Hints)Tetsuya Morimoto
38.1K views39 slides
ソーシャルゲームのためのデータベース設計 by
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
124.4K views33 slides
プログラミングコンテストでの動的計画法 by
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法Takuya Akiba
91.6K views59 slides
ネットワーク ゲームにおけるTCPとUDPの使い分け by
ネットワーク ゲームにおけるTCPとUDPの使い分けネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けモノビット エンジン
61.4K views63 slides
最適輸送入門 by
最適輸送入門最適輸送入門
最適輸送入門joisino
11.6K views88 slides
SSII2020SS: 微分可能レンダリングの最新動向 〜「見比べる」ことによる3次元理解 〜​ by
SSII2020SS:  微分可能レンダリングの最新動向 〜「見比べる」ことによる3次元理解 〜​SSII2020SS:  微分可能レンダリングの最新動向 〜「見比べる」ことによる3次元理解 〜​
SSII2020SS: 微分可能レンダリングの最新動向 〜「見比べる」ことによる3次元理解 〜​SSII
6.2K views37 slides

More Related Content

What's hot

Python 3.9からの新定番zoneinfoを使いこなそう by
Python 3.9からの新定番zoneinfoを使いこなそうPython 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそうRyuji Tsutsui
6.9K views42 slides
DockerコンテナでGitを使う by
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使うKazuhiro Suga
18.8K views8 slides
メタプログラミングって何だろう by
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろうKota Mizushima
28.7K views16 slides
SAT/SMTソルバの仕組み by
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みMasahiro Sakai
36.7K views51 slides
Pythonはどうやってlen関数で長さを手にいれているの? by
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Takayuki Shimizukawa
38.1K views56 slides
組み込み関数(intrinsic)によるSIMD入門 by
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門Norishige Fukushima
47.5K views122 slides

What's hot(20)

Python 3.9からの新定番zoneinfoを使いこなそう by Ryuji Tsutsui
Python 3.9からの新定番zoneinfoを使いこなそうPython 3.9からの新定番zoneinfoを使いこなそう
Python 3.9からの新定番zoneinfoを使いこなそう
Ryuji Tsutsui6.9K views
DockerコンテナでGitを使う by Kazuhiro Suga
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga18.8K views
メタプログラミングって何だろう by Kota Mizushima
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
Kota Mizushima28.7K views
SAT/SMTソルバの仕組み by Masahiro Sakai
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
Masahiro Sakai36.7K views
Pythonはどうやってlen関数で長さを手にいれているの? by Takayuki Shimizukawa
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?
Takayuki Shimizukawa38.1K views
組み込み関数(intrinsic)によるSIMD入門 by Norishige Fukushima
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
Norishige Fukushima47.5K views
それはYAGNIか? それとも思考停止か? by Yoshitaka Kawashima
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
Yoshitaka Kawashima29.3K views
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門 by Tadahiro Ishisaka
関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門関数型・オブジェクト指向宗教戦争に疲れたなたに送るGo言語入門
関数型・オブジェクト指向 宗教戦争に疲れたなたに送るGo言語入門
Tadahiro Ishisaka11.2K views
「今日から使い切る」 ための GNU Parallel による並列処理入門 by Koji Matsuda
「今日から使い切る」ための GNU Parallelによる並列処理入門「今日から使い切る」ための GNU Parallelによる並列処理入門
「今日から使い切る」 ための GNU Parallel による並列処理入門
Koji Matsuda21.6K views
世界一わかりやすいClean Architecture by Atsushi Nakamura
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
Atsushi Nakamura47.1K views
何となく勉強した気分になれるパーサ入門 by masayoshi takahashi
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
masayoshi takahashi35.8K views
2値分類・多クラス分類 by t dev
2値分類・多クラス分類2値分類・多クラス分類
2値分類・多クラス分類
t dev15.8K views
PHPからgoへの移行で分かったこと by gree_tech
PHPからgoへの移行で分かったことPHPからgoへの移行で分かったこと
PHPからgoへの移行で分かったこと
gree_tech6.4K views
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models by Deep Learning JP
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models
【DL輪読会】Llama 2: Open Foundation and Fine-Tuned Chat Models
Deep Learning JP1.4K views
[DL輪読会]Decision Transformer: Reinforcement Learning via Sequence Modeling by Deep Learning JP
[DL輪読会]Decision Transformer: Reinforcement Learning via Sequence Modeling[DL輪読会]Decision Transformer: Reinforcement Learning via Sequence Modeling
[DL輪読会]Decision Transformer: Reinforcement Learning via Sequence Modeling
Deep Learning JP2.9K views
強化学習における好奇心 by Shota Imai
強化学習における好奇心強化学習における好奇心
強化学習における好奇心
Shota Imai3.3K views
NumPyが物足りない人へのCython入門 by Shiqiao Du
NumPyが物足りない人へのCython入門NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門
Shiqiao Du36.8K views
超実践 Cloud Spanner 設計講座 by Samir Hammoudi
超実践 Cloud Spanner 設計講座超実践 Cloud Spanner 設計講座
超実践 Cloud Spanner 設計講座
Samir Hammoudi21.3K views

Similar to Pythonと型チェッカー

20170131 python3 6 PEP526 by
20170131 python3 6 PEP526 20170131 python3 6 PEP526
20170131 python3 6 PEP526 masahitojp
3.3K views35 slides
Introduction of Python by
Introduction of PythonIntroduction of Python
Introduction of PythonTomoya Nakayama
1.2K views45 slides
はじめてのPython by
はじめてのPythonはじめてのPython
はじめてのPythonKatsumi Honda
4.4K views47 slides
Python standard 2022 Spring by
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
218 views47 slides
TensorFlowをもう少し詳しく入門 by
TensorFlowをもう少し詳しく入門TensorFlowをもう少し詳しく入門
TensorFlowをもう少し詳しく入門tak9029
18.5K views186 slides
ひのきのぼうだけで全クリ目指す by
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すAromaBlack
1.5K views35 slides

Similar to Pythonと型チェッカー(20)

20170131 python3 6 PEP526 by masahitojp
20170131 python3 6 PEP526 20170131 python3 6 PEP526
20170131 python3 6 PEP526
masahitojp3.3K views
はじめてのPython by Katsumi Honda
はじめてのPythonはじめてのPython
はじめてのPython
Katsumi Honda4.4K views
Python standard 2022 Spring by anyakichi
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
anyakichi218 views
TensorFlowをもう少し詳しく入門 by tak9029
TensorFlowをもう少し詳しく入門TensorFlowをもう少し詳しく入門
TensorFlowをもう少し詳しく入門
tak902918.5K views
ひのきのぼうだけで全クリ目指す by AromaBlack
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
AromaBlack1.5K views
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30) by Hiro H.
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)
Hiro H.4K views
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用 by de:code 2017
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
de:code 20178.3K views
Learning Template Library Design using Boost.Geomtry by Akira Takahashi
Learning Template Library Design using Boost.GeomtryLearning Template Library Design using Boost.Geomtry
Learning Template Library Design using Boost.Geomtry
Akira Takahashi3.4K views
dataclassとtypehintを使ってますか? by Atsushi Hayakawa
dataclassとtypehintを使ってますか?dataclassとtypehintを使ってますか?
dataclassとtypehintを使ってますか?
Atsushi Hayakawa1.4K views
Pythonによる機械学習入門 ~Deep Learningに挑戦~ by Yasutomo Kawanishi
Pythonによる機械学習入門 ~Deep Learningに挑戦~Pythonによる機械学習入門 ~Deep Learningに挑戦~
Pythonによる機械学習入門 ~Deep Learningに挑戦~
Yasutomo Kawanishi86.6K views
Introduction to Numpy (and Python) [JPN] by MasaruOinaga
Introduction to Numpy (and Python) [JPN]Introduction to Numpy (and Python) [JPN]
Introduction to Numpy (and Python) [JPN]
MasaruOinaga132 views
「深層学習」勉強会LT資料 "Chainer使ってみた" by Ken'ichi Matsui
「深層学習」勉強会LT資料 "Chainer使ってみた"「深層学習」勉強会LT資料 "Chainer使ってみた"
「深層学習」勉強会LT資料 "Chainer使ってみた"
Ken'ichi Matsui14K views
Chainerの使い方と自然言語処理への応用 by Seiya Tokui
Chainerの使い方と自然言語処理への応用Chainerの使い方と自然言語処理への応用
Chainerの使い方と自然言語処理への応用
Seiya Tokui53.2K views
魂のコーディング by Daisuke Tasaki
魂のコーディング魂のコーディング
魂のコーディング
Daisuke Tasaki2.3K views
Python 学習教材 (~299ページ) by Jun MITANI
Python 学習教材 (~299ページ)Python 学習教材 (~299ページ)
Python 学習教材 (~299ページ)
Jun MITANI249.3K views

More from Tetsuya Morimoto

ビジネスパーソン x プログラミング by
ビジネスパーソン x プログラミングビジネスパーソン x プログラミング
ビジネスパーソン x プログラミングTetsuya Morimoto
499 views22 slides
チケット駆動開発のススメ by
チケット駆動開発のススメチケット駆動開発のススメ
チケット駆動開発のススメTetsuya Morimoto
525 views23 slides
PyLadies Tokyo 二周年記念パーティ LT by
PyLadies Tokyo 二周年記念パーティ LTPyLadies Tokyo 二周年記念パーティ LT
PyLadies Tokyo 二周年記念パーティ LTTetsuya Morimoto
1K views7 slides
PyCon JP 2016 ビギナーセッション by
PyCon JP 2016 ビギナーセッションPyCon JP 2016 ビギナーセッション
PyCon JP 2016 ビギナーセッションTetsuya Morimoto
1.4K views6 slides
Hyper Introduction by
Hyper IntroductionHyper Introduction
Hyper IntroductionTetsuya Morimoto
1.7K views20 slides
ストリーミングのげんざい by
ストリーミングのげんざいストリーミングのげんざい
ストリーミングのげんざいTetsuya Morimoto
87.7K views22 slides

More from Tetsuya Morimoto(16)

ビジネスパーソン x プログラミング by Tetsuya Morimoto
ビジネスパーソン x プログラミングビジネスパーソン x プログラミング
ビジネスパーソン x プログラミング
Tetsuya Morimoto499 views
チケット駆動開発のススメ by Tetsuya Morimoto
チケット駆動開発のススメチケット駆動開発のススメ
チケット駆動開発のススメ
Tetsuya Morimoto525 views
PyLadies Tokyo 二周年記念パーティ LT by Tetsuya Morimoto
PyLadies Tokyo 二周年記念パーティ LTPyLadies Tokyo 二周年記念パーティ LT
PyLadies Tokyo 二周年記念パーティ LT
Tetsuya Morimoto1K views
PyCon JP 2016 ビギナーセッション by Tetsuya Morimoto
PyCon JP 2016 ビギナーセッションPyCon JP 2016 ビギナーセッション
PyCon JP 2016 ビギナーセッション
Tetsuya Morimoto1.4K views
ストリーミングのげんざい by Tetsuya Morimoto
ストリーミングのげんざいストリーミングのげんざい
ストリーミングのげんざい
Tetsuya Morimoto87.7K views
Python3 プログラミング勉強会 by Tetsuya Morimoto
Python3 プログラミング勉強会Python3 プログラミング勉強会
Python3 プログラミング勉強会
Tetsuya Morimoto13.2K views
Ikazuchi introduction for Europython 2011 LT by Tetsuya Morimoto
Ikazuchi introduction for Europython 2011 LTIkazuchi introduction for Europython 2011 LT
Ikazuchi introduction for Europython 2011 LT
Tetsuya Morimoto687 views
Python界隈の翻訳プロジェクト by Tetsuya Morimoto
Python界隈の翻訳プロジェクトPython界隈の翻訳プロジェクト
Python界隈の翻訳プロジェクト
Tetsuya Morimoto3.5K views

Recently uploaded

Windows 11 information that can be used at the development site by
Windows 11 information that can be used at the development siteWindows 11 information that can be used at the development site
Windows 11 information that can be used at the development siteAtomu Hidaka
89 views41 slides
SNMPセキュリティ超入門 by
SNMPセキュリティ超入門SNMPセキュリティ超入門
SNMPセキュリティ超入門mkoda
420 views15 slides
SSH応用編_20231129.pdf by
SSH応用編_20231129.pdfSSH応用編_20231129.pdf
SSH応用編_20231129.pdficebreaker4
366 views13 slides
光コラボは契約してはいけない by
光コラボは契約してはいけない光コラボは契約してはいけない
光コラボは契約してはいけないTakuya Matsunaga
24 views17 slides
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20... by
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...NTT DATA Technology & Innovation
132 views42 slides

Recently uploaded(10)

Windows 11 information that can be used at the development site by Atomu Hidaka
Windows 11 information that can be used at the development siteWindows 11 information that can be used at the development site
Windows 11 information that can be used at the development site
Atomu Hidaka89 views
SNMPセキュリティ超入門 by mkoda
SNMPセキュリティ超入門SNMPセキュリティ超入門
SNMPセキュリティ超入門
mkoda420 views
SSH応用編_20231129.pdf by icebreaker4
SSH応用編_20231129.pdfSSH応用編_20231129.pdf
SSH応用編_20231129.pdf
icebreaker4366 views
光コラボは契約してはいけない by Takuya Matsunaga
光コラボは契約してはいけない光コラボは契約してはいけない
光コラボは契約してはいけない
Takuya Matsunaga24 views
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20... by NTT DATA Technology & Innovation
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...
今、改めて考えるPostgreSQLプラットフォーム - マルチクラウドとポータビリティ -(PostgreSQL Conference Japan 20...
The Things Stack説明資料 by The Things Industries by CRI Japan, Inc.
The Things Stack説明資料 by The Things IndustriesThe Things Stack説明資料 by The Things Industries
The Things Stack説明資料 by The Things Industries
CRI Japan, Inc.73 views
速習! PostgreSQL専用HAソフトウェア: Patroni(PostgreSQL Conference Japan 2023 発表資料) by NTT DATA Technology & Innovation
速習! PostgreSQL専用HAソフトウェア: Patroni(PostgreSQL Conference Japan 2023 発表資料)速習! PostgreSQL専用HAソフトウェア: Patroni(PostgreSQL Conference Japan 2023 発表資料)
速習! PostgreSQL専用HAソフトウェア: Patroni(PostgreSQL Conference Japan 2023 発表資料)

Pythonと型チェッカー

  • 2. 自己紹介 ● 森本 哲也 – twitter: @t2y ● ポータルサイトの会社 – オブジェクトストレージの開発・運用 ● 業務では Go 言語で開発 – 普段使いのツールやプロトタイピングに Python ● エキスパート Python プログラミング改訂2版 – Python 3.5 ( 翻訳は 3.6) を対象
  • 3. 最近のニュース ● Pyre: Fast Type Checking for Python – 概要から引用 Facebook 社も Instagram 社も大規模に Python を使っています。私たちは Python の表現力、 柔軟性、開発における生産性をとても好んでいます。しかし、数百万行といった大規模コード ベースの保守を考えると、そういった良いところにも陰りがみえてきます。 ● 静的な保証がないと、既存のコードベースを安全に変更することが難しくなり、コードのエラーが発生しや すくなって静的型付けされたコードと比べて開発が遅くなる ● コード検索、コード補完、ナビゲーション、リファクタリングサポートなどの高品質なツールを構築するこ とが難しい。こういったツールがないと、大規模コードベースで作業するときに特に弊害となる これらの問題に対処するために、私たちは高速な PEP 484 互換の型チェッカーと深い静的解析 ツールを構築するための優れたプラットフォームの双方を兼ね備えた Pyre を構築しました。
  • 4. 型ヒント付きコードのサンプル 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)
  • 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 のコア機能の拡張は保守的に進められる 新規の機能がいきなり言語のコアに入ることは基本的にない イマココ!
  • 10. mypy daemon ● mypy 0.600 でサポート – まだ beta レベル ● 数ファイル変更したときに毎回 mypy を実行す るのはパフォーマンスがよくない ● dmypy を使うと大規模なコードベースでは mypy コマンドと比べて数十倍速いらしい
  • 11. 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
  • 12. 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' エラーになって計測できなかった。。。
  • 13. TypedDict(1) ● mypy_extensions の拡張機能 – 試験的機能だが、 mypy 0.530 から公式サポート ● 厳密なディクショナリの型定義 – 特定の key のみに限定したいとき – value の型が複数あるようなとき – すべての要素を指定させたいとき
  • 14. 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 が型推論する
  • 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_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')
  • 17. NamedTuple(1) ● TypedDict 同様に 3.6 からクラス構文をつかっ た NamedTuple の定義ができる
  • 18. 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"
  • 19. 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 の型定義は継承できない
  • 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 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] を返す
  • 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
  • 27. デコレート関数の型チェック 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)
  • 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")
  • 31. 型ヒント関連の 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
  • 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): 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
  • 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 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 でインターフェースっぽいもの
  • 43. ユーザー定義プロトコル (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 を継承しなくて良い!
  • 44. ユーザー定義プロトコル (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)
  • 45. ユーザー定義プロトコル (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 エラーメッセージもわかりやすい
  • 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 import setup 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 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 を作る
  • 49. 型情報の 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 を作る
  • 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 よりも高速らしい
  • 61. 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
  • 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 Hinting in PyCharm – PEP 563 アノテーションの評価の延期 – 型ヒントや変数アノテーションのサポート – Typeshed との連携 ● Pyre: https://pyre-check.org/ – 高速でスケーラブルな型チェッカー
  • 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 のコードベースへ移行? ● 型アノテーションの自動生成の未来 – いまツールが公開されたところ
  • 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 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!
  • 72. その他のツール ● 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