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

Will Python type checker respect __annotations__ set dynamically?

所以我正在阅读 PEP 563 -- Postponed Evaluation of Annotations,上面写着:

In Python 3.10, function and variable annotations will no longer be evaluated at definition time. Instead, a string form will be preserved in the respective __annotations__ dictionary. Static type checkers will see no difference in behavior, whereas tools using annotations at runtime will have to perform postponed evaluation.

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

def f(foo: str):
    pass

相当于这个表格?

def f(foo):
    pass

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

我测试了mypy,PyCharm和pytype,都不尊重动态添加的__annotations__。所以我的问题是:

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

您可以将注释存储为字符串,或者换句话说,您可以使用字符串进行注释:

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

这是 useful/necessary 否则你会得到无法解析的循环引用:

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 类型检查器是疯狂的。

PEP 563 是关于注释的延迟评估。这与 是否 注释存储在 __annotations__ 属性中无关。注释已经并将存储在 __annotations__ 中,只是存储格式发生了变化。

句子

Static type checkers will see no difference in behavior

实际上与您的想法相反:类型检查器从未检查过__annotations__属性,因此不会发现任何差异。


这样考虑带注释的函数 ff.__annotations__

def f(foo: str): ...

print(f.__annotations__)

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

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

使用 from __future__ import annotations 启用 PEP 563,这将打印:

{'foo': 'str'} 

换句话说,__annotations__值的类型发生了变化,但注解本身没有任何区别。由于类型检查器检查的是实际注释,而不是 __annotations__ 属性,因此它们“也不会看到行为上的差异”。