Python中类型注释的自引用或转发引用

Lir*_*una 12 python typing typechecking python-3.x python-3.5

我试图找出类型的自引用如何与python3的类型注释一起工作 - 文档没有指定任何关于此的内容.

举个例子:

from typing import TypeVar, Optional, Generic

T = TypeVar('T')
class Node(Generic[T]):
    left = None
    right = None
    value = None

    def __init__(
        self, value: Optional[T],
        left: Optional[Node[T]]=None,
        right: Optional[Node[T]]=None,
    ) -> None:
        self.value = value
        self.left = left
        self.right = right
Run Code Online (Sandbox Code Playgroud)

此代码生成错误:

Traceback (most recent call last):
  File "node.py", line 4, in <module>
    class Node(Generic[T]):
  File "node.py", line 12, in Node
    right: Optional[Node[T]]=None,
NameError: name 'Node' is not defined
Run Code Online (Sandbox Code Playgroud)

这是使用Python 3.5.1

fal*_*tru 17

PEP 0484 - 类型提示 - 前向声明的问题解决了这个问题:

类型提示的问题在于,在定义函数时评估注释(每个PEP 3107,类似于默认值),因此在定义函数时必须已经定义了注释中使用的任何名称.常见的场景是类定义,其方法需要在注释中引用类本身.(更一般地,它也可以与相互递归的类一起出现.)这对于容器类型是很自然的,例如:

...

如上所述,这将无法工作,因为Python中的特性是一旦类的整个主体被执行,类名就会被定义.我们的解决方案不是特别优雅,而是完成工作,是允许在注释中使用字符串文字. 大多数情况下你不必使用它 - 大多数类型提示的使用都应该引用其他模块中定义的内置类型或类型.

from typing import TypeVar, Optional, Generic

T = TypeVar('T')
class Node(Generic[T]):
    left = None
    right = None
    value = None

    def __init__(
        self,
        value: Optional[T],
        left: Optional['Node[T]']=None,
        right: Optional['Node[T]']=None,
    ) -> None:
        self.value = value
        self.left = left
        self.right = right
Run Code Online (Sandbox Code Playgroud)
>>> import typing
>>> typing.get_type_hints(Node.__init__)
{'return': None,
 'value': typing.Union[~T, NoneType],
 'left': typing.Union[__main__.Node[~T], NoneType],
 'right': typing.Union[__main__.Node[~T], NoneType]}
Run Code Online (Sandbox Code Playgroud)

  • @user1312695,如果您使用的是Python 3.7+,“from __future__ import comments”将允许您使用“Optional[Node[T]]”。https://www.python.org/dev/peps/pep-0563/ (6认同)