Python 中类型注释的自引用或前向引用
Self-reference or forward-reference of type annotations in Python
我正在尝试弄清楚类型的自引用如何与 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
PEP 0484 - Type Hints - The problem of forward declarations 解决了问题:
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:
...
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.
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]}
我正在尝试弄清楚类型的自引用如何与 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
PEP 0484 - Type Hints - The problem of forward declarations 解决了问题:
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:
...
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.
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]}