首页 > 解决方案 > 非泛型类型的不同运行时行为

问题描述

考虑以下两种情况:

from queue import Queue
my_q: Queue[int] = Queue()
print(f"queue={my_q}")

from queue import Queue

class MyClass(object):
    def __init__(self):
        self.my_q: Queue[int] = Queue()

my_class = MyClass()
print(f"queue={my_class.my_q}")

运行前者(预期)会抛出TypeError

$ python3 run.py
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    my_q: Queue[int] = Queue()
TypeError: 'type' object is not subscriptable

然而后者没有,并且没有问题地继续打印语句:

$ python3 run.py
queue=<queue.Queue object at 0x7fb40265f730>

我希望TypeError在这两种情况下都有一个。TypeErrorQueue[int]类型在类的方法内部时,为什么没有__init__

标签: pythonpython-3.8

解决方案


模块和类注释都可以在运行时访问,因此可以评估:

# example.py
a: int = 4
print(__annotations__)  # {'a': <class 'int'>}

相反,函数的本地注释是不可访问的,因此永远不会被评估。


根据PEP 3107,函数参数注释在运行时被评估并可用:

编译后,函数的注释可通过函数的__annotations__属性获得。

根据PEP 526 ,简单名称的模块和类级别注释在运行时进行评估和可用。为了提高效率,函数内部的注释没有被明确地评估或存储:

此外,在模块或类级别,如果被注释的项目是一个简单的名称,那么它和注释将__annotations__作为从名称到评估的注释的有序映射存储在该模块或类的属性中(如果私有,则被破坏) .
[...]
此外,在本地提供注释的价值并不能抵消必须在每个函数调用上创建和填充注释字典的成本。因此,功能级别的注释不会被评估和存储。

使用PEP 563 / Python 3.10,不再立即评估注释。但是,模块、类和函数参数名称的注释仍然可能被延迟评估,因此应该是有效的表达式。函数的局部注释仍然无法访问,因此无法评估。

请注意,根据 PEP 526,根本不评估局部变量注释,因为它们在函数闭包之外无法访问。


推荐阅读