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

时间:2016-03-24 04:57:56

标签: python python-3.x python-3.5 typechecking typing

我正在尝试弄清楚类型的自引用如何与python3's type annotations一起使用 - 文档没有指明任何与此有关的内容。

举个例子:

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

此代码生成错误:

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

这是使用Python 3.5.1

1 个答案:

答案 0 :(得分:15)

PEP 0484 - Type Hints - The problem of forward declarations解决了这个问题:

  

类型提示的问题是注释(每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
>>> 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]}