以下代码:
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 – Postponed Evaluation of Annotations时:
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
对象?
答案 0 :(得分:3)
除非需要,否则使用PEP 536的目的是不评估注释。签名仅报告注释。
如果出于您的目的需要解析注释,则必须自己解决。 PEP 536告诉documents how you do this:
对于使用类型提示的代码,
typing.get_type_hints(obj, globalns=None, localns=None)
函数可以从其字符串形式正确地返回表达式。[...]
对于将注释用于其他目的的代码,常规的eval(ann,globals,locals)调用足以解析注释。
您甚至可以在获得签名之前使用typing.get_type_hints()
function分配回__annotations__
:
import typing
Example.__new__.__annotations__ = typing.get_type_hints(Example.__new__)
signature: inspect.Signature = inspect.signature(Example)
即使未使用from __future__ import annotations
,这样做也是安全的。
答案 1 :(得分:1)
首先,让我们运行另一个示例:
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
。
答案 2 :(得分:0)
您必须实际使用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)
或者,您可以在调用__annotations__
之前修改inspect.signature(obj)
,但是我发现这太难了,因为我需要涵盖多种不同的情况。
@Martijn Pieters的答案缺少有关typing.get_type_hints
的一个细节:
如有必要,如果设置的默认值等于无,则添加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)