SlideShare a Scribd company logo
Python と型ヒント
2015-10-10 Tetsuya Morimoto
自己紹介
●
森本 哲也
– twitter: @t2y
●
白ヤギコーポレーション所属
– カメリオAPI開発 ( 興味がある方はブースへ )
●
エキスパート Python プログラミング共訳
●
プログラミング言語歴
– Python (3 年 )
– → Java (3 年 )
– → Go ( 半年 )
求人
●
自然言語処理や機械学習の技術を駆使して製品
開発をしたい人募集!
Pythonのパラドックス
●
2004 年 8 月 Paul Graham
– Python を学ぼうとするプログラマーは賢い
●
Python 2.3.4 (2004-05-27): 2.3 の時代
– 新しい言語を学ぶ人たちはプログラミングが好き
であり、仕事に役立つから学ぶわけではない
– 曲解 : 「優秀な Java プログラマーを採用したかっ
たら Python プログラマーを雇えば良い」
●
いまは成り立たない
Python3 のパラドックス
●
2015 年 10 月
– Python3 を現場に導入しようとするプログラマーは
賢い
– Python3 を導入する人たちはプログラミングが好き
であり、現場で役立つから導入するわけではない
– 曲解 : 「優秀な Python プログラマーを採用した
かったら Python3 を現場に導入すれば良い」
●
それっぽい? ( 自己責任で! )
概要
●
背景
– 漸進的型付け→関数アノテーション→ mypy
●
PEP 484 〜型ヒント〜
– 目的
– 型ヒントのために定義された型 (Any, Union, etc)
– ジェネリクス
●
懸念
– 型ヒントの批判、 Typed Clojure の現在
●
展望
– 構造的部分型 (Structual Subtyping) へ
Python3.5
背景
背景 : 漸進的型付け (Gradual Typing)
●
Jeremy Siek 氏と Walid Taha 氏が 2006 年に
考案した型システム
– 静的型付けと動的型付けを組み合わせられる
– 双方の型システムの良いとこ取りしたもの
– Object 型ではなく Any 型を導入しなければならな
い背景の説明
●
PEP 484 の理論的背景
●
入門記事 : 漸進的型付けとは何か
背景 : 関数アノテーション (PEP3017)
●
Python3.0 で導入 (PEP3017)
– 2008-12-03 リリース
– 関数に任意のアノテーションを書く仕組み
●
PEP 484 を支える基本的な仕組み
– 関数アノテーションの用途を型アノテーションに
限定した
– 関数オブジェクトの __annotations__ 属性に保持
されるのは同じ
背景 :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
背景 :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 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"
型ヒント : 目的
●
型アノテーションの構文を標準化
●
静的解析
– Lint ツール ( オフライン型チェッカー )
●
IDE
– コード補完やリファクタリング機能に利用
– Type Hinting in PyCharm
●
ドキュメンテーション
– 型アノテーションがそのまま使える?
Python は
動的型付け言語
型ヒント :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 + ("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 型の操作は型チェカーでエラーとなる
理論的背景は「漸進的型付けとは何か」を参照
型ヒント : 直和型 (Union Type)
●
直和型
– 関数型プログラミング言語でよく使われるデータ型
– 典型的にはツリーのデータ構造を簡潔に表現できる
●
単一の引数に対して少数の期待される型の集合
をとる
e = Union[Employee, Sequence[Employee]]
# OCaml バリアント型
type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
# 第7回「代数データ型」でいろいろなデータを表してみる
型ヒント :Optional 型
●
直和型の応用
●
Union[T1, None] と Optional[T1] は等価
– None を取り得ることが明示される
– None は多くの操作が型エラー
●
Java の NullPointerException はこりごり
– @Nonnull, @Nullable のアノテーションを明示
– Collections.emptyList(), Collections.emptyMap()
●
Null 安全を型システムで保証する世界へ
型ヒント :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'
型ヒント : ジェネリクス
●
コンテナー内の要素に期待する型を示す
●
TypeVar というファクトリーを使って型変数を
定義する
from typing import Sequence, TypeVar
T = TypeVar('T') # Declare type variable
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
型ヒント :TypeVar
●
TypeVar のコンストラクタに渡す型変数を表す
文字列と代入する変数名は同じでなければいけ
ない
from typing import TypeVar
X = TypeVar('X') # correct
Z = TypeVar('Y') # error
mypy
generics_typevar.py:4: error: Unexpected TypeVar() argument value
型ヒント :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)
型の別名
型ヒント : 型別名と直和型
●
型別名と直和型の違い
– 型パラメーターとなり得るか
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[...]
型ヒント : ユーザー定義ジェネリック型
●
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)
型ヒント : 型消去
●
ユーザー定義のジェネリック型はインスタンス
化できる
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]
型ヒント : 数値型階層 (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"
型ヒント : スタブファイル
●
型チェッカーのための拡張モジュール
●
型ヒントを Python モジュールではなく外部の
ファイルに書き出すためのもの
●
拡張子は .pyi
●
主には ( 型ヒントがない ) サードパーティのラ
イブラリと一緒に型ヒントを使うため
– スタブを集める typeshedリポジトリもある
●
TypeScript でいうところの DefinitelyTyped
型ヒント : スタブの例
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
型ヒント : その他
●
呼び出し可能オブジェクト
●
抽象ジェネリック型
●
上界をもつ型変数
●
共変性と反変性
●
前方参照
●
キャスト
●
...
PEP 484 を読んでください ...
懸念
懸念 :(Python に ) 必要か?
●
Python に型ヒントは本当に必要なのか?
●
Revenge of the Types: 型の復讐 (翻訳)
– Armin Ronacher 氏の問題提起
– 欲しいのは強力な型システムそのもの ≠型ヒント
●
代数的データ型 (Algebraic data type) の議論
– Python は言語の意味論が壊れてる?
●
Python 側実装と C 言語側実装による意味論の違い
●
CPython インタープリターの最適化のため
懸念 :Typed Clojure の現状
●
Why we’re no longer using Core.typed
●
CircleCI が本番環境で 2 年間使っていたが、止
めてしまった話
– 型チェックが遅くてインタラクティブに開発でき
ない
– core.typed が Clojure 言語全てをカバーしてない
– サードパーティライブラリの型アノテーションの
メンテが大変
展望
展望 : 構造的部分型 (Structual Subtyping)
●
構造的部分型の型チェックの前提案
– プロトコルという概念を導入
●
Sized, Iterable, Iterator など
– クラスの継承関係ではなく、メソッド実装の有無
で型チェックを行う (Go 言語のポリモルフィズム )
– うまくいけば 3.6 の PEP に出てくるかも?
●
クラスの継承関係で部分型を定義するのを公称
的部分型 (Nominal Subtyping) と言う
展望 : 構造的部分型への期待?
●
[Python-ideas] Structural type checking for
PEP 484
– Cory Benfield (hyper の作者 ) からの返信
– 自分は型ヒントに特に関心のない開発者の 1 人
だったんだけど、これは型チェックに関して懸念
していたことに対応できるものだと思う
まとめ
型ヒントの所感
●
型ヒントが成功を収めるかどうかは懐疑的
– 型ヒントが Python3 のキラーアプリというのは
まだ楽観的過ぎると私は思う→プロパガンダ
●
みんな強力な型システムを求めている
– NullPointerException の発生しない世界
●
型システムとプログラミングの関係を学ぶ
– プログラミングの幅が広がり楽しくなる!
Happy Coding
With Type Hints

More Related Content

Python と型ヒント (Type Hints)

  • 2. 自己紹介 ● 森本 哲也 – twitter: @t2y ● 白ヤギコーポレーション所属 – カメリオAPI開発 ( 興味がある方はブースへ ) ● エキスパート Python プログラミング共訳 ● プログラミング言語歴 – Python (3 年 ) – → Java (3 年 ) – → Go ( 半年 )
  • 4. Pythonのパラドックス ● 2004 年 8 月 Paul Graham – Python を学ぼうとするプログラマーは賢い ● Python 2.3.4 (2004-05-27): 2.3 の時代 – 新しい言語を学ぶ人たちはプログラミングが好き であり、仕事に役立つから学ぶわけではない – 曲解 : 「優秀な Java プログラマーを採用したかっ たら Python プログラマーを雇えば良い」 ● いまは成り立たない
  • 5. Python3 のパラドックス ● 2015 年 10 月 – Python3 を現場に導入しようとするプログラマーは 賢い – Python3 を導入する人たちはプログラミングが好き であり、現場で役立つから導入するわけではない – 曲解 : 「優秀な Python プログラマーを採用した かったら Python3 を現場に導入すれば良い」 ● それっぽい? ( 自己責任で! )
  • 6. 概要 ● 背景 – 漸進的型付け→関数アノテーション→ mypy ● PEP 484 〜型ヒント〜 – 目的 – 型ヒントのために定義された型 (Any, Union, etc) – ジェネリクス ● 懸念 – 型ヒントの批判、 Typed Clojure の現在 ● 展望 – 構造的部分型 (Structual Subtyping) へ Python3.5
  • 8. 背景 : 漸進的型付け (Gradual Typing) ● Jeremy Siek 氏と Walid Taha 氏が 2006 年に 考案した型システム – 静的型付けと動的型付けを組み合わせられる – 双方の型システムの良いとこ取りしたもの – Object 型ではなく Any 型を導入しなければならな い背景の説明 ● PEP 484 の理論的背景 ● 入門記事 : 漸進的型付けとは何か
  • 9. 背景 : 関数アノテーション (PEP3017) ● Python3.0 で導入 (PEP3017) – 2008-12-03 リリース – 関数に任意のアノテーションを書く仕組み ● PEP 484 を支える基本的な仕組み – 関数アノテーションの用途を型アノテーションに 限定した – 関数オブジェクトの __annotations__ 属性に保持 されるのは同じ
  • 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. 背景 :mypy プロジェクト (2) ● 現時点の mypy ができること – GIL のない VM – 型アノテーション→ PEP 484 で標準化 – 静的型チェッカーとしての Lint ツール ● PEP 484 では型チェッカーは提供しない
  • 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. 型ヒント : 目的 ● 型アノテーションの構文を標準化 ● 静的解析 – Lint ツール ( オフライン型チェッカー ) ● IDE – コード補完やリファクタリング機能に利用 – Type Hinting in PyCharm ● ドキュメンテーション – 型アノテーションがそのまま使える? Python は 動的型付け言語
  • 16. 型ヒント :Any 型 ● 全ての型は Any 型のサブタイプ – object 型と似ているが、型チェッカーによる扱い が異なる ● object 型 – 型チェッカーは値のほとんどの操作を拒否する ● Any 型 – 型チェッカーは値の全ての操作を許容する
  • 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. 型ヒント : 直和型 (Union Type) ● 直和型 – 関数型プログラミング言語でよく使われるデータ型 – 典型的にはツリーのデータ構造を簡潔に表現できる ● 単一の引数に対して少数の期待される型の集合 をとる e = Union[Employee, Sequence[Employee]] # OCaml バリアント型 type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat # 第7回「代数データ型」でいろいろなデータを表してみる
  • 19. 型ヒント :Optional 型 ● 直和型の応用 ● Union[T1, None] と Optional[T1] は等価 – None を取り得ることが明示される – None は多くの操作が型エラー ● Java の NullPointerException はこりごり – @Nonnull, @Nullable のアノテーションを明示 – Collections.emptyList(), Collections.emptyMap() ● Null 安全を型システムで保証する世界へ
  • 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. 型ヒント : ジェネリクス ● コンテナー内の要素に期待する型を示す ● TypeVar というファクトリーを使って型変数を 定義する from typing import Sequence, TypeVar T = TypeVar('T') # Declare type variable def first(l: Sequence[T]) -> T: # Generic function return l[0]
  • 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. 型ヒント :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. 型ヒント : 型別名と直和型 ● 型別名と直和型の違い – 型パラメーターとなり得るか 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. 型ヒント : ユーザー定義ジェネリック型 ● 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. 型ヒント : 型消去 ● ユーザー定義のジェネリック型はインスタンス 化できる 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. 型ヒント : 数値型階層 (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. 型ヒント : スタブファイル ● 型チェッカーのための拡張モジュール ● 型ヒントを Python モジュールではなく外部の ファイルに書き出すためのもの ● 拡張子は .pyi ● 主には ( 型ヒントがない ) サードパーティのラ イブラリと一緒に型ヒントを使うため – スタブを集める typeshedリポジトリもある ● TypeScript でいうところの DefinitelyTyped
  • 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
  • 32. 懸念 :(Python に ) 必要か? ● Python に型ヒントは本当に必要なのか? ● Revenge of the Types: 型の復讐 (翻訳) – Armin Ronacher 氏の問題提起 – 欲しいのは強力な型システムそのもの ≠型ヒント ● 代数的データ型 (Algebraic data type) の議論 – Python は言語の意味論が壊れてる? ● Python 側実装と C 言語側実装による意味論の違い ● CPython インタープリターの最適化のため
  • 33. 懸念 :Typed Clojure の現状 ● Why we’re no longer using Core.typed ● CircleCI が本番環境で 2 年間使っていたが、止 めてしまった話 – 型チェックが遅くてインタラクティブに開発でき ない – core.typed が Clojure 言語全てをカバーしてない – サードパーティライブラリの型アノテーションの メンテが大変
  • 35. 展望 : 構造的部分型 (Structual Subtyping) ● 構造的部分型の型チェックの前提案 – プロトコルという概念を導入 ● Sized, Iterable, Iterator など – クラスの継承関係ではなく、メソッド実装の有無 で型チェックを行う (Go 言語のポリモルフィズム ) – うまくいけば 3.6 の PEP に出てくるかも? ● クラスの継承関係で部分型を定義するのを公称 的部分型 (Nominal Subtyping) と言う
  • 36. 展望 : 構造的部分型への期待? ● [Python-ideas] Structural type checking for PEP 484 – Cory Benfield (hyper の作者 ) からの返信 – 自分は型ヒントに特に関心のない開発者の 1 人 だったんだけど、これは型チェックに関して懸念 していたことに対応できるものだと思う
  • 38. 型ヒントの所感 ● 型ヒントが成功を収めるかどうかは懐疑的 – 型ヒントが Python3 のキラーアプリというのは まだ楽観的過ぎると私は思う→プロパガンダ ● みんな強力な型システムを求めている – NullPointerException の発生しない世界 ● 型システムとプログラミングの関係を学ぶ – プログラミングの幅が広がり楽しくなる!