__origin__
という属性がどこからやってきたのを調べていたところ、 PEP 585 -- Type Hinting Generics In Standard Collections という PEP を見つけたので、本来の目的を忘れて流し読みしてました。まだ Draft ステータスですので、今後採用されるかどうかはわかりませんが、自分の理解をメモに残しておきます。
概要
- これまでの型アノテーションでは、コレクションを表現するのに専用の型を使っていた (
typing.List
やtyping.Dict
など) - コレクションの実装クラスと型クラスを統合し、標準のコレクションクラス(
list
やdict
など)で型アノテーションできるようにしよう - いずれ
typing
配下のジェネリックコレクション型は廃止したい
用語
- Generic
- パラメータ化可能な型。一般的にはコンテナを指す。
- 別名 parametric type、generic type とも。
- 例:
dict
- parametrized generic
- コンテナ要素の型を指定した Generic のインスタンス
- 別名 parametrized type とも。
- 例:
dict[str, int]
アプローチ
これまでの typing.List
や typing.Dict
の代わりに、 list
や dict
を用いる。以上。
def find(haystack: dict[str, list[int]]) -> int:
...
やらないこと
-
isinstance(obj, list[int])
には対応しない -
issubclass(cls, list[str])
にも対応しない
メモ
内部的には types.GenericAlias
のインスタンスを作ることを想定している。そのため、 __origin__
や __args__
を使って型情報を取り出せる。
StrList = list[str]
assert isinstance(StrList, types.GenericAlias)
assert StrList.__origin__ is list
assert StrList.__args__ is (str,)
感想
- 普段使うクラスとは別に、アノテーション専用の型があるのはシンプルではないので、これはとてもよさそう (もう慣れてしまったけど)
- typing のジェネリック型が廃止されるとき (5年後ぐらい?) に古いコードで悲鳴が上がりそうでつらい
- Python3 のバージョンが進むにつれて、型アノテーションまわりが Python の言語仕様に強く結びついていくのを感じる。
- 未だに型チェッカーは外にあるけれど、Python を書くときは形を書くべきという流れになっていきそうな…
- パフォーマンスやテストで使われ始めるともう止められない予感がする
追記
いつのまにか PEP 585 の採用が決まっており(Accepted)、3.9.0a6 で使えるようになっていました。以下、少し前にインストールした 3.9-dev での様子です。
$ python3.9
Python 3.9.0a6+ (heads/master:7f7e706, May 9 2020, 13:35:20)
[Clang 11.0.3 (clang-1103.0.32.59)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> list[int]
list[int]
>>> dict[str, int]
dict[str, int]
>>> tuple[int, ...]
tuple[int, ...]