Python类型标注的自引用或前引用[duplicate]

时间:2020-12-31 11:24:22

This question already has an answer here:

这个问题已经有了答案:

I'm trying to figure out how self-reference of types work with python3's type annotations - the docs don't specify anything regarding this.

我正试图弄明白类型的自引用是如何与python3的类型注释一起工作的——文档中并没有对此做任何规定。

As an example:

作为一个例子:

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

This code generates the error:

此代码生成错误:

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

This is using Python 3.5.1

这使用的是Python 3.5.1

1 个解决方案

#1


15  

PEP 0484 - Type Hints - The problem of forward declarations addresses the issue:

PEP 0484 -类型提示-转发声明的问题解决这个问题:

The problem with type hints is that annotations (per PEP 3107 , and similar to default values) are evaluated at the time a function is defined, and thus any names used in an annotation must be already defined when the function is being defined. A common scenario is a class definition whose methods need to reference the class itself in their annotations. (More general, it can also occur with mutually recursive classes.) This is natural for container types, for example:

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

...

As written this will not work, because of the peculiarity in Python that class names become defined once the entire body of the class has been executed. Our solution, which isn't particularly elegant, but gets the job done, is to allow using string literals in annotations. Most of the time you won't have to use this though -- most uses of type hints are expected to reference builtin types or types defined in other modules.

正如编写的那样,这将不起作用,因为在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]}

#1


15  

PEP 0484 - Type Hints - The problem of forward declarations addresses the issue:

PEP 0484 -类型提示-转发声明的问题解决这个问题:

The problem with type hints is that annotations (per PEP 3107 , and similar to default values) are evaluated at the time a function is defined, and thus any names used in an annotation must be already defined when the function is being defined. A common scenario is a class definition whose methods need to reference the class itself in their annotations. (More general, it can also occur with mutually recursive classes.) This is natural for container types, for example:

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

...

As written this will not work, because of the peculiarity in Python that class names become defined once the entire body of the class has been executed. Our solution, which isn't particularly elegant, but gets the job done, is to allow using string literals in annotations. Most of the time you won't have to use this though -- most uses of type hints are expected to reference builtin types or types defined in other modules.

正如编写的那样,这将不起作用,因为在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]}