Python 类型检查器会尊重动态设置的 __annotations__ 吗?

问题描述 投票:0回答:2

所以我正在阅读PEP 563——推迟注释评估,其中写道:

在Python 3.10中,函数和变量注释将不再在定义时评估。相反,字符串形式将保留在相应的

__annotations__
字典中。 静态类型检查器在行为上不会发现任何差异,而在运行时使用注释的工具将必须执行推迟的评估。

这让我想知道,如果类型检查器实现了这个 PEP 的建议,这是否意味着

def f(foo: str):
    pass

相当于这个形式?

def f(foo):
    pass

f.__annotations__ = {"foo": "str"}

我测试了mypy、PyCharm和pytype,都不尊重动态添加的

__annotations__
。所以我的问题是:

我的理解是否正确,类型检查器最终会支持它,还是我误解了 PEP?

python python-typing
2个回答
1
投票

PEP 563 是关于注释的“推迟评估”。这与 注释是否存储在 __annotations__ 属性内无关。注释已经并将存储在

__annotations__
中,只是存储格式发生了变化。
句子

静态类型检查器不会发现行为上的差异

实际上与您的想法相反:类型检查器
never

已经检查了__annotations__属性,因此不会看到任何差异。


考虑带注释的函数
f

f.__annotations__
def f(foo: str): ...

print(f.__annotations__)

在 Python 3.9 或更早版本中,将打印:

{'foo': <class 'str'>}

使用 
from __future__ import annotations

启用 PEP 563,将打印:

{'foo': 'str'} 

换句话说,
__annotations__

值的类型发生了变化,但注释本身没有显示任何差异。由于类型检查器检查实际注释,而不是

__annotations__
属性,因此它们“也不会看到行为上的差异”。
    


1
投票

def f(foo: 'bar') -> 'baz': ...

当您获得无法解析的循环引用时,这是有用/必要的:

class Foo: def bar() -> Foo: # doesn't resolve, Foo not defined yet ... def baz() -> 'Foo': # "workaround" ...

from __future__ import annotations

可以透明地实现这一点,即即使在写入

-> Foo
时,它也会被评估为
-> 'Foo'
。此行为将成为 3.10 中的默认行为。
类型检查器不会看到任何差异,因为它们必须已经处理了这种行为。

类型检查器不会动态评估

__annotations__

,因为这意味着它们需要实际

执行
代码,这显然会产生副作用,因此对于static类型检查器来说是疯狂的。

© www.soinside.com 2019 - 2024. All rights reserved.