web-dev-qa-db-ja.com

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を使用しています

15
LiraNuna

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