繁体   English   中英

使用 PEP 563 检查签名

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM