Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Python と型ヒント
2015-10-10 Tetsuya Morimoto
自己紹介
●
森本 哲也
– twitter: @t2y
●
白ヤギコーポレーション所属
– カメリオAPI開発 ( 興味がある方はブースへ )
●
エキスパート Python プログラミング共訳
●
プログラミング言語歴
– Python (...
求人
●
自然言語処理や機械学習の技術を駆使して製品
開発をしたい人募集!
Pythonのパラドックス
●
2004 年 8 月 Paul Graham
– Python を学ぼうとするプログラマーは賢い
●
Python 2.3.4 (2004-05-27): 2.3 の時代
– 新しい言語を学ぶ人たちはプログラミン...
Python3 のパラドックス
●
2015 年 10 月
– Python3 を現場に導入しようとするプログラマーは
賢い
– Python3 を導入する人たちはプログラミングが好き
であり、現場で役立つから導入するわけではない
– 曲解 :...
概要
●
背景
– 漸進的型付け→関数アノテーション→ mypy
●
PEP 484 〜型ヒント〜
– 目的
– 型ヒントのために定義された型 (Any, Union, etc)
– ジェネリクス
●
懸念
– 型ヒントの批判、 Typed C...
背景
背景 : 漸進的型付け (Gradual Typing)
●
Jeremy Siek 氏と Walid Taha 氏が 2006 年に
考案した型システム
– 静的型付けと動的型付けを組み合わせられる
– 双方の型システムの良いとこ取りしたもの...
背景 : 関数アノテーション (PEP3017)
●
Python3.0 で導入 (PEP3017)
– 2008-12-03 リリース
– 関数に任意のアノテーションを書く仕組み
●
PEP 484 を支える基本的な仕組み
– 関数アノテーシ...
背景 :mypy プロジェクト (1)
●
http://mypy-lang.org/
●
作者 : Jukka Lehtosalo 氏
– プログラマーを 6 年、マネージャーを 2 年
– 2009 年からケンブリッジ大学の博士課程
●
2...
背景 :mypy プロジェクト (2)
●
現時点の mypy ができること
– GIL のない VM
– 型アノテーション→ PEP 484 で標準化
– 静的型チェッカーとしての Lint ツール
●
PEP 484 では型チェッカーは提供...
PEP 484
型ヒント
型ヒント : サンプルコード
# -*- coding: utf-8 -*-
import json
import sys
from pprint import pformat
from typing import Any, Dict
def ...
型ヒント : 目的
●
型アノテーションの構文を標準化
●
静的解析
– Lint ツール ( オフライン型チェッカー )
●
IDE
– コード補完やリファクタリング機能に利用
– Type Hinting in PyCharm
●
ドキュメ...
型ヒント :Sphinx
俺がやる!
型ヒント :Any 型
●
全ての型は Any 型のサブタイプ
– object 型と似ているが、型チェッカーによる扱い
が異なる
●
object 型
– 型チェッカーは値のほとんどの操作を拒否する
●
Any 型
– 型チェッカーは値の全て...
any_and_object.py: note: In function "object_func":
any_and_object.py:8: error: Unsupported left operand type
for + ("obje...
型ヒント : 直和型 (Union Type)
●
直和型
– 関数型プログラミング言語でよく使われるデータ型
– 典型的にはツリーのデータ構造を簡潔に表現できる
●
単一の引数に対して少数の期待される型の集合
をとる
e = Union[Em...
型ヒント :Optional 型
●
直和型の応用
●
Union[T1, None] と Optional[T1] は等価
– None を取り得ることが明示される
– None は多くの操作が型エラー
●
Java の NullPointe...
型ヒント :Optional 型の例
from typing import Optional, Union
def func1(data: Optional[int]) -> int:
return 3 + data
def func2(dat...
型ヒント : ジェネリクス
●
コンテナー内の要素に期待する型を示す
●
TypeVar というファクトリーを使って型変数を
定義する
from typing import Sequence, TypeVar
T = TypeVar('T') ...
型ヒント :TypeVar
●
TypeVar のコンストラクタに渡す型変数を表す
文字列と代入する変数名は同じでなければいけ
ない
from typing import TypeVar
X = TypeVar('X') # correct
Z...
型ヒント :TypeVar の例
●
typing モジュールにいくつか定義されてる
# Some unconstrained type variables. These are used by the container types.
T =...
型ヒント : 型別名と直和型
●
型別名と直和型の違い
– 型パラメーターとなり得るか
from typing import Generic, TypeVar, Union
AnyStr = TypeVar('AnyStr', str, byt...
型ヒント : ユーザー定義ジェネリック型
●
Generic という抽象基底クラスを継承する
from typing import Generic, TypeVar
T = TypeVar('T')
class Stack(Generic[T]...
型ヒント : 型消去
●
ユーザー定義のジェネリック型はインスタンス
化できる
from typing import TypeVar, Generic
T = TypeVar('T')
class Node(Generic[T]):
...
x...
型ヒント : 数値型階層 (numeric tower)
●
numbers モジュールに抽象基底クラスを定義
complex 型 int/float 型を許容する
def add_int(num: int) -> int:
return nu...
型ヒント : スタブファイル
●
型チェッカーのための拡張モジュール
●
型ヒントを Python モジュールではなく外部の
ファイルに書き出すためのもの
●
拡張子は .pyi
●
主には ( 型ヒントがない ) サードパーティのラ
イブラリ...
型ヒント : スタブの例
class tzinfo:
def tzname(self, dt: Optional[datetime]) -> str: ...
def utcoffset(self, dt: Optional[datetime]...
型ヒント : その他
●
呼び出し可能オブジェクト
●
抽象ジェネリック型
●
上界をもつ型変数
●
共変性と反変性
●
前方参照
●
キャスト
●
...
PEP 484 を読んでください ...
懸念
懸念 :(Python に ) 必要か?
●
Python に型ヒントは本当に必要なのか?
●
Revenge of the Types: 型の復讐 (翻訳)
– Armin Ronacher 氏の問題提起
– 欲しいのは強力な型システムそのも...
懸念 :Typed Clojure の現状
●
Why we’re no longer using Core.typed
●
CircleCI が本番環境で 2 年間使っていたが、止
めてしまった話
– 型チェックが遅くてインタラクティブに開発...
展望
展望 : 構造的部分型 (Structual Subtyping)
●
構造的部分型の型チェックの前提案
– プロトコルという概念を導入
●
Sized, Iterable, Iterator など
– クラスの継承関係ではなく、メソッド実装の...
展望 : 構造的部分型への期待?
●
[Python-ideas] Structural type checking for
PEP 484
– Cory Benfield (hyper の作者 ) からの返信
– 自分は型ヒントに特に関心のな...
まとめ
型ヒントの所感
●
型ヒントが成功を収めるかどうかは懐疑的
– 型ヒントが Python3 のキラーアプリというのは
まだ楽観的過ぎると私は思う→プロパガンダ
●
みんな強力な型システムを求めている
– NullPointerException...
Happy Coding
With Type Hints
Upcoming SlideShare
Loading in …5
×

Python と型ヒント (Type Hints)

25,985 views

Published on

PyCon JP 2015

Published in: Technology

Python と型ヒント (Type Hints)

  1. 1. Python と型ヒント 2015-10-10 Tetsuya Morimoto
  2. 2. 自己紹介 ● 森本 哲也 – twitter: @t2y ● 白ヤギコーポレーション所属 – カメリオAPI開発 ( 興味がある方はブースへ ) ● エキスパート Python プログラミング共訳 ● プログラミング言語歴 – Python (3 年 ) – → Java (3 年 ) – → Go ( 半年 )
  3. 3. 求人 ● 自然言語処理や機械学習の技術を駆使して製品 開発をしたい人募集!
  4. 4. Pythonのパラドックス ● 2004 年 8 月 Paul Graham – Python を学ぼうとするプログラマーは賢い ● Python 2.3.4 (2004-05-27): 2.3 の時代 – 新しい言語を学ぶ人たちはプログラミングが好き であり、仕事に役立つから学ぶわけではない – 曲解 : 「優秀な Java プログラマーを採用したかっ たら Python プログラマーを雇えば良い」 ● いまは成り立たない
  5. 5. Python3 のパラドックス ● 2015 年 10 月 – Python3 を現場に導入しようとするプログラマーは 賢い – Python3 を導入する人たちはプログラミングが好き であり、現場で役立つから導入するわけではない – 曲解 : 「優秀な Python プログラマーを採用した かったら Python3 を現場に導入すれば良い」 ● それっぽい? ( 自己責任で! )
  6. 6. 概要 ● 背景 – 漸進的型付け→関数アノテーション→ mypy ● PEP 484 〜型ヒント〜 – 目的 – 型ヒントのために定義された型 (Any, Union, etc) – ジェネリクス ● 懸念 – 型ヒントの批判、 Typed Clojure の現在 ● 展望 – 構造的部分型 (Structual Subtyping) へ Python3.5
  7. 7. 背景
  8. 8. 背景 : 漸進的型付け (Gradual Typing) ● Jeremy Siek 氏と Walid Taha 氏が 2006 年に 考案した型システム – 静的型付けと動的型付けを組み合わせられる – 双方の型システムの良いとこ取りしたもの – Object 型ではなく Any 型を導入しなければならな い背景の説明 ● PEP 484 の理論的背景 ● 入門記事 : 漸進的型付けとは何か
  9. 9. 背景 : 関数アノテーション (PEP3017) ● Python3.0 で導入 (PEP3017) – 2008-12-03 リリース – 関数に任意のアノテーションを書く仕組み ● PEP 484 を支える基本的な仕組み – 関数アノテーションの用途を型アノテーションに 限定した – 関数オブジェクトの __annotations__ 属性に保持 されるのは同じ
  10. 10. 背景 :mypy プロジェクト (1) ● http://mypy-lang.org/ ● 作者 : Jukka Lehtosalo 氏 – プログラマーを 6 年、マネージャーを 2 年 – 2009 年からケンブリッジ大学の博士課程 ● 2012 PyCon Finland – MYPY: A PYTHON VARIANT WITH SEAMLESS DYNA MIC AND STATIC TYPING ● 静的型付けと動的型付けの融合 – PyPy や Cython がライバル、 GIL のない VM
  11. 11. 背景 :mypy プロジェクト (2) ● 現時点の mypy ができること – GIL のない VM – 型アノテーション→ PEP 484 で標準化 – 静的型チェッカーとしての Lint ツール ● PEP 484 では型チェッカーは提供しない
  12. 12. PEP 484 型ヒント
  13. 13. 型ヒント : サンプルコード # -*- coding: utf-8 -*- 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() -> None: raw_data = sys.argv[1] # type: str data = pretty_format(json.loads(raw_data)) print(data) data.append('mypy') main() $ mypy tutorial.py tutorial.py: note: In function "main": tutorial.py:14: error: "str" has no attribute "append"
  14. 14. 型ヒント : 目的 ● 型アノテーションの構文を標準化 ● 静的解析 – Lint ツール ( オフライン型チェッカー ) ● IDE – コード補完やリファクタリング機能に利用 – Type Hinting in PyCharm ● ドキュメンテーション – 型アノテーションがそのまま使える? Python は 動的型付け言語
  15. 15. 型ヒント :Sphinx 俺がやる!
  16. 16. 型ヒント :Any 型 ● 全ての型は Any 型のサブタイプ – object 型と似ているが、型チェッカーによる扱い が異なる ● object 型 – 型チェッカーは値のほとんどの操作を拒否する ● Any 型 – 型チェッカーは値の全ての操作を許容する
  17. 17. any_and_object.py: note: In function "object_func": any_and_object.py:8: error: Unsupported left operand type for + ("object") 型ヒント :Any 型と object 型 from typing import Any def any_func(x: Any, y: Any) -> Any: return x + y def object_func(x: object, y: object) -> object: return x + y mypy object 型の操作は型チェカーでエラーとなる 理論的背景は「漸進的型付けとは何か」を参照
  18. 18. 型ヒント : 直和型 (Union Type) ● 直和型 – 関数型プログラミング言語でよく使われるデータ型 – 典型的にはツリーのデータ構造を簡潔に表現できる ● 単一の引数に対して少数の期待される型の集合 をとる e = Union[Employee, Sequence[Employee]] # OCaml バリアント型 type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat # 第7回「代数データ型」でいろいろなデータを表してみる
  19. 19. 型ヒント :Optional 型 ● 直和型の応用 ● Union[T1, None] と Optional[T1] は等価 – None を取り得ることが明示される – None は多くの操作が型エラー ● Java の NullPointerException はこりごり – @Nonnull, @Nullable のアノテーションを明示 – Collections.emptyList(), Collections.emptyMap() ● Null 安全を型システムで保証する世界へ
  20. 20. 型ヒント :Optional 型の例 from typing import Optional, Union def func1(data: Optional[int]) -> int: return 3 + data def func2(data: Union[int, None]) -> int: return 3 + data def func3(data: int=None) -> int: return 3 + data これらは等価な型ヒント ・デフォルト引数に None を指定したときも Optional 型として扱う TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
  21. 21. 型ヒント : ジェネリクス ● コンテナー内の要素に期待する型を示す ● TypeVar というファクトリーを使って型変数を 定義する from typing import Sequence, TypeVar T = TypeVar('T') # Declare type variable def first(l: Sequence[T]) -> T: # Generic function return l[0]
  22. 22. 型ヒント :TypeVar ● TypeVar のコンストラクタに渡す型変数を表す 文字列と代入する変数名は同じでなければいけ ない from typing import TypeVar X = TypeVar('X') # correct Z = TypeVar('Y') # error mypy generics_typevar.py:4: error: Unexpected TypeVar() argument value
  23. 23. 型ヒント :TypeVar の例 ● typing モジュールにいくつか定義されてる # Some unconstrained type variables. These are used by the container types. T = TypeVar('T') # Any type. KT = TypeVar('KT') # Key type. VT = TypeVar('VT') # Value type. T_co = TypeVar('T_co', covariant=True) # Any type covariant containers. V_co = TypeVar('V_co', covariant=True) # Any type covariant containers. VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers. T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant. # A useful type variable with constraints. This represents string types. # TODO: What about bytearray, memoryview? AnyStr = TypeVar('AnyStr', bytes, str) 型の別名
  24. 24. 型ヒント : 型別名と直和型 ● 型別名と直和型の違い – 型パラメーターとなり得るか from typing import Generic, TypeVar, Union AnyStr = TypeVar('AnyStr', str, bytes) class AnyStrNode(Generic[AnyStr]): ... UnionStr = Union[str, bytes] class UnionStrNode(Generic[UnionStr]): ... mypy error: Free type variable expected in Generic[...]
  25. 25. 型ヒント : ユーザー定義ジェネリック型 ● Generic という抽象基底クラスを継承する from typing import Generic, TypeVar T = TypeVar('T') class Stack(Generic[T]): def __init__(self) -> None: self.items = [] # type: List[T] def push(self, item: T) -> None: self.items.append(item) def pop(self) -> T: return self.items.pop() s = Stack() # type: Stack[int] s.push(3) s.push(5) s.pop() s.push('x') s = Stack[int]() ... mypy mypy generics_stack.py:19: error: Argument 1 to "push" of "Stack" has incompatible type "str"; expected "int" error: Generic type not valid as an expression any more (use '# type:' comment instead)
  26. 26. 型ヒント : 型消去 ● ユーザー定義のジェネリック型はインスタンス 化できる from typing import TypeVar, Generic T = TypeVar('T') class Node(Generic[T]): ... x = Node[T]() # The type inferred for x is Node[T]. print('x.__class__:', x.__class__) y = Node[int]() # The type inferred for y is Node[int]. print('y.__class__:', y.__class__) z = Node() # Inferred type is Node[Any]. print('z.__class__:', z.__class__) 実行時に型情報は 保持していない $ python generics_type_erasure.py x.__class__: __main__.Node[~T] y.__class__: __main__.Node[~T] z.__class__: __main__.Node[~T]
  27. 27. 型ヒント : 数値型階層 (numeric tower) ● numbers モジュールに抽象基底クラスを定義 complex 型 int/float 型を許容する def add_int(num: int) -> int: return num + 1 print(add_int(1)) print(add_int(2.4)) print(add_int(complex('3+4J'))) # floatは割愛 def add_complex(num: complex) -> complex: return num + complex('1+2J') print(add_complex(7)) print(add_complex(8.14)) print(add_complex(complex('9+10J'))) mypy error: Argument 1 to "add_int" has incompatible type "float"; expected "int" error: Argument 1 to "add_int" has incompatible type "complex"; expected "int"
  28. 28. 型ヒント : スタブファイル ● 型チェッカーのための拡張モジュール ● 型ヒントを Python モジュールではなく外部の ファイルに書き出すためのもの ● 拡張子は .pyi ● 主には ( 型ヒントがない ) サードパーティのラ イブラリと一緒に型ヒントを使うため – スタブを集める typeshedリポジトリもある ● TypeScript でいうところの DefinitelyTyped
  29. 29. 型ヒント : スタブの例 class tzinfo: def tzname(self, dt: Optional[datetime]) -> str: ... def utcoffset(self, dt: Optional[datetime]) -> int: ... def dst(self, dt: Optional[datetime]) -> int: ... def fromutc(self, dt: datetime) -> datetime: .. class timezone(tzinfo): utc = ... # type: tzinfo min = ... # type: tzinfo max = ... # type: tzinfo def __init__(self, offset: timedelta, name: str = '') -> None: ... def __hash__(self) -> int: ... datetime.pyi
  30. 30. 型ヒント : その他 ● 呼び出し可能オブジェクト ● 抽象ジェネリック型 ● 上界をもつ型変数 ● 共変性と反変性 ● 前方参照 ● キャスト ● ... PEP 484 を読んでください ...
  31. 31. 懸念
  32. 32. 懸念 :(Python に ) 必要か? ● Python に型ヒントは本当に必要なのか? ● Revenge of the Types: 型の復讐 (翻訳) – Armin Ronacher 氏の問題提起 – 欲しいのは強力な型システムそのもの ≠型ヒント ● 代数的データ型 (Algebraic data type) の議論 – Python は言語の意味論が壊れてる? ● Python 側実装と C 言語側実装による意味論の違い ● CPython インタープリターの最適化のため
  33. 33. 懸念 :Typed Clojure の現状 ● Why we’re no longer using Core.typed ● CircleCI が本番環境で 2 年間使っていたが、止 めてしまった話 – 型チェックが遅くてインタラクティブに開発でき ない – core.typed が Clojure 言語全てをカバーしてない – サードパーティライブラリの型アノテーションの メンテが大変
  34. 34. 展望
  35. 35. 展望 : 構造的部分型 (Structual Subtyping) ● 構造的部分型の型チェックの前提案 – プロトコルという概念を導入 ● Sized, Iterable, Iterator など – クラスの継承関係ではなく、メソッド実装の有無 で型チェックを行う (Go 言語のポリモルフィズム ) – うまくいけば 3.6 の PEP に出てくるかも? ● クラスの継承関係で部分型を定義するのを公称 的部分型 (Nominal Subtyping) と言う
  36. 36. 展望 : 構造的部分型への期待? ● [Python-ideas] Structural type checking for PEP 484 – Cory Benfield (hyper の作者 ) からの返信 – 自分は型ヒントに特に関心のない開発者の 1 人 だったんだけど、これは型チェックに関して懸念 していたことに対応できるものだと思う
  37. 37. まとめ
  38. 38. 型ヒントの所感 ● 型ヒントが成功を収めるかどうかは懐疑的 – 型ヒントが Python3 のキラーアプリというのは まだ楽観的過ぎると私は思う→プロパガンダ ● みんな強力な型システムを求めている – NullPointerException の発生しない世界 ● 型システムとプログラミングの関係を学ぶ – プログラミングの幅が広がり楽しくなる!
  39. 39. Happy Coding With Type Hints

×