Самостоятельная ссылка или прямая ссылка на аннотации типов в Python

Я пытаюсь выяснить, как самооценка типов работает с аннотациями типа 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

Этот код генерирует ошибку:

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

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

>>> 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]}