今日気づいたのですが、Python 3.10 の inspect モジュールでは typing.get_type_hints()
を使って型を解釈するようになりました。該当のコミットはこちらです。
これは Python 3.10 からデフォルトで有効になるアノテーションの遅延評価に関連する修正のようです。obj.__annotations__
に詰まっている型アノテーション情報が文字列となるので、typing.get_type_hints()
に任せるのが適当であるという判断でしょう。
この変更により、単に obj.__annotations__
を参照していた inspect.signature()
の型情報が、もう一歩踏み込んだ解析結果に切り替わるということになります。
たとえば、Python 3.9 では次の hello()
関数の引数 name
は str
型と扱われています。
$ python3.9
Python 3.9.0 (default, Oct 24 2020, 15:41:29)
[Clang 11.0.3 (clang-1103.0.32.59)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def hello(name: str = None):
... print("Hello ", name)
...
>>> import inspect
>>> inspect.signature(hello)
<Signature (name: str = None)>
一方、Python 3.10 (開発中)では Optional[str]
型とみなされます。デフォルト引数が None
であることを見て、より適した型を返すようになっているわけです。
$ python3.10
Python 3.10.0a1+ (heads/master:805ef73, Oct 24 2020, 15:07:19)
[Clang 11.0.3 (clang-1103.0.32.59)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def hello(name: str = None):
... print("Hello ", name)
...
>>> import inspect
>>> inspect.signature(hello)
<Signature (name: Optional[str] = None)>
ちなみに、実行時に名前解決ができない場合(typing.TYPE_CHECKING
で実行時は import していない場合など) はこれまで通り obj.__signature__
を参照するため、アノテーションによっては解釈結果が変化します。
$ python3.10
Python 3.10.0a1+ (heads/master:805ef73, Oct 24 2020, 15:07:19)
[Clang 11.0.3 (clang-1103.0.32.59)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def hello(name: Unknown, age: int = None): pass
...
>>> import inspect
>>> inspect.signature(hello)
<Signature (name: 'Unknown', age: 'int' = None)>
このケースでは Unknown
型が解決できないため、引数 age
の型は Optional[int]
ではなく、単なる int
になります。