非泛型类型的不同运行时行为

Different runtime behavior for non-generic typing

考虑这两种情况:

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。当 Queue[int] 类型位于 class 的 __init__ 方法内部时,为什么没有 TypeError

这可能是由于 python 评估类型提示的方式,以及根据语句是否在函数内而有所不同。所述类型提示在 python 3.8 中无效(尽管在 3.9 中不存在)并且可能根本不会在 init 方法中进行评估。

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

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

相比之下,函数的局部注释不可访问,因此永远不会被评估。


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

Once compiled, a function's annotations are available via the function's __annotations__ attribute.

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

In addition, at the module or class level, if the item being annotated is a simple name, then it and the annotation will be stored in the __annotations__ attribute of that module or class (mangled if private) as an ordered mapping from names to evaluated annotations.
[...]
Also the value of having annotations available locally does not offset the cost of having to create and populate the annotations dictionary on every function call. Therefore, annotations at function level are not evaluated and not stored.

使用 PEP 563 / Python 3.10,不再立即评估注释。但是,模块注释、class 和函数参数名称仍可能被惰性求值,因此应该是有效的表达式。函数局部注释仍然不可访问,因此未计算。

Note that as per PEP 526, local variable annotations are not evaluated at all since they are not accessible outside of the function's closure.