[英]inspect.signature with PEP 563
以下代码:
import inspect
from typing import NamedTuple
class Example(NamedTuple):
a: str
if __name__== "__main__":
signature: inspect.Signature = inspect.signature(Example)
print(signature)
输出:
(a: str)
但是,当启用PEP 563 – 注释的推迟评估时:
from __future__ import annotations
import inspect
from typing import NamedTuple
class Example(NamedTuple):
a: str
if __name__== "__main__":
signature: inspect.Signature = inspect.signature(Example)
print(signature)
输出是:
(a: 'str')
我怎样才能像没有它一样使用 PEP 563 获得类型为inspect.Signature
的完全相同的对象?
除非需要,否则使用 PEP 536 的目的是不要评估注释。 签名仅报告注释。
如果出于您的目的,您需要解析注释,您必须自己这样做。 PEP 536 告诉文档您如何执行此操作:
对于使用类型提示的代码,
typing.get_type_hints(obj, globalns=None, localns=None)
函数正确地从其字符串形式计算表达式。[...]
对于将注释用于其他目的的代码,常规的 eval(ann, globals, locals) 调用足以解析注释。
您甚至可以在获取签名之前使用typing.get_type_hints()
函数将其分配回__annotations__
:
import typing
Example.__new__.__annotations__ = typing.get_type_hints(Example.__new__)
signature: inspect.Signature = inspect.signature(Example)
即使未使用from __future__ import annotations
这样做也是安全的。
您必须实际使用eval
来获得相同的行为:
from __future__ import annotations
import inspect
from typing import NamedTuple
class Example(NamedTuple):
a: str
signature: inspect.Signature = inspect.signature(Example)
print(signature)
# extra bit
globalns = getattr(Example, '__globals__', {})
for param in list(signature.parameters.values()):
if isinstance(param.annotation, str):
param._annotation = eval(param.annotation, globalns)
print(signature)
你会得到:
(a: 'str')
(a: str)
或者,您可以在调用inspect.signature(obj)
之前修改__annotations__
,但我发现它太难了,因为我需要涵盖多种不同的情况。
@Martijn Pieters 的回答遗漏了一个关于typing.get_type_hints
细节:
如有必要,如果设置了等于 None 的默认值,则添加 Optional[t]
例子:
# without imporing annotations from __future__
import inspect
import typing
def func(a: str=None): pass
print(inspect.signature(func))
func.__annotations__ = typing.get_type_hints(func)
print(inspect.signature(func))
你会得到:
(a: str = None)
(a: Union[str, NoneType] = None)
首先,让我们运行一个不同的例子:
signature: inspect.Signature = inspect.signature(Example)
print(signature)
print(Example.__annotations__)
这打印:
(a: str)
OrderedDict([('a', <class 'str'>)])
到目前为止,一切都很好,正如我们所期望的那样,我们有 或Signature
和我们的__anotations__
。
现在让我们对第二个例子做同样的事情,它打印:
(a: 'str')
OrderedDict([('a', ForwardRef('str'))])
所以你在这里没有得到相同的Signature
。 一个为您提供实际类,另一个为typing.ForwardRef
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.