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__
属性,因此不会发现任何差异。
这样考虑带注释的函数 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__
属性,因此它们“也不会看到行为上的差异”。
所以我正在阅读 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__
属性,因此不会发现任何差异。
这样考虑带注释的函数 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__
属性,因此它们“也不会看到行为上的差异”。