昨日に引き続いて __origin__ という属性について調べていたら、PEP 560 -- Core support for typing module and generic types という PEP にたどり着きました。この PEP は 3.7 から採用されているので、すでに実装が存在して触ることができるやつです。
概要
- 型ヒントが登場したとき、Python 本体に手を入れないように設計していた
- しかし、当時(バージョン 3.6)は 3つの問題があった
-
typingモジュールのパフォーマンス - メタクラスの競合
-
typingモジュールで使われている多数のハック
-
アプローチ
-
__class_getitem__、__mro_entries__というふたつのスペシャルメソッドを追加する -
__class_getitem__- クラスオブジェクト向けの
__getitem__ -
Iterable[int]などの場面で利用される
- クラスオブジェクト向けの
-
__mro_entries__- クラスではないオブジェクトから派生クラスを作るときに呼び出される
-
__mro_entries__が返したクラスをもとに派生クラスの MRO を決定する -
typing._GenericAliasを実現するための仕掛け-
List[int]の__mro_entries__はlistを返すので、実行時はlistのサブクラスとして振る舞う
-
- クラス定義時の継承クラスは
__orig_base__に、解決済みの継承クラスは__base__に保存される
感想
-
typing._GenericAliasが生まれましたきっかけとなる PEP を読みました - この PEP を読んでから
typingモジュールを読むとわかりやすいです - PEP をあさり始めた目的であった
__origin__は、__mro_entries__を実現するためのプライベートな属性だったというオチでした -
__class_getitem__もうまく使うとハックしがいがありそうですね