解压缩Python的类型注释

fre*_*bie 7 python annotations type-hinting inspect python-3.x

我试图通过使用模块中的signature()函数,基于我在一些Python函数中提供的类型注释生成一些JavaScript inspect.

当类型是一个简单的内置类时,这部分可以正常工作:

import inspect

def my_function() -> dict:
    pass

signature = inspect.signature(my_function)
signature.return_annotation is dict  # True
Run Code Online (Sandbox Code Playgroud)

虽然我不知道如何打开和检查更复杂的注释,例如:

from typing import List
import inspect

def my_function() -> List[int]:
    pass

signature = inspect.signature(my_function)
signature.return_annotation is List[int]  # False
Run Code Online (Sandbox Code Playgroud)

再次引用自定义类的类似问题:

def my_function() -> List['User']:
    pass
...
signature.return_annotation  # typing.List[_ForwardRef('User')]
Run Code Online (Sandbox Code Playgroud)

我想要的是这样的 - 所以我可以在生成JavaScript时适当地分支:

type = signature.return_annotation... # list
member_type = signature.return_annotation... # int / 'User'
Run Code Online (Sandbox Code Playgroud)

谢谢.

Phi*_*lip 7

List不是类型映射到GenericMeta,尽管有语法。每次访问它都会生成一个新实例:

>>> [ id(List[str]) for i in range(3) ]
[33105112, 33106872, 33046936]
Run Code Online (Sandbox Code Playgroud)

这意味着即使List[int] is not List[int]. 要比较两个实例,您有多种选择:

  • 使用==,即signature.return_annotation == List[int]
  • 将您的类型的实例存储在全局变量中并进行检查,即,

    a = List[int]
    def foo() -> a:
        pass
    inspect.signature(foo).return_annotation is a
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用issubclass. 打字模块定义了这一点。请注意,这可能比您想要的更多,_TypeAlias如果您使用它,请务必阅读文档。

  • List仅核对并自己阅读内容。尽管该属性是内部的,但实现不太可能很快改变:List[int].__args__[0]包含从 Python 3.5.2 开始的类型参数,在早期版本中,它的List[int].__parameters__[0].

如果您想为导出器编写通用代码,那么最后一个选项可能是最好的。如果您只需要涵盖特定用例,我个人会使用==.


小智 5

Python的3.8提供了typing.get_origin()typing.get_args()此!

assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)

assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)
Run Code Online (Sandbox Code Playgroud)

请参阅https://docs.python.org/3/library/typing.html#typing.get_origin