web-dev-qa-db-ja.com

メソッド内の引数の型ヒントとしてクラスを使用する

以下に含めたコードは、次のエラーをスローします。

NameError: name 'Vector2' is not defined 

この行で:

def Translate (self, pos: Vector2):

PythonがTranslateメソッドのVector2クラスを認識しないのはなぜですか?

class Vector2:

    def __init__(self, x: float, y: float):

        self.x = x
        self.y = y

    def Translate(self, pos: Vector2):

        self.x += pos.x
        self.y += pos.y
23
Vanitas

(クラス本体のコンパイル中に)Translateに遭遇したとき、Vector2はまだ定義されていないためです(現在コンパイル中であり、名前バインディングは実行されていません)。 Python当然文句を言います。

これはそのような一般的なシナリオ(そのクラスの本体でクラスを型指定する)であるため、前方参照を使用して囲む必要があります引用符で囲みます:

class Vector2:    
    # __init__ as defined

    def Translate(self, pos: 'Vector2'):    
        self.x += pos.x
        self.y += pos.y

Python(およびPEP 484に準拠するチェッカー)はヒントを理解し、適切に登録します。 Pythonは、__annotations__typing.get_type_hints を介してアクセスされるときにこれを認識します:

from typing import get_type_hints

get_type_hints(Vector2(1,2).Translate)
{'pos': __main__.Vector2}

これはPython 3.7;以下の 以下のabarnertの回答 を参照してください。

あなたが求めている機能はフォワード(タイプ)参照と呼ばれ、それはPython 3.7以降( PEP 56 )に追加されました。1 したがって、これは現在有効です。

from __future__ import annotations
class C:
    def spam(self, other: C) -> C:
        pass

__future__ステートメント 。これは必要になります 4.0まで

残念ながら、Python 3.6以前では、この機能は使用できないため、 Jim Fasarakis Hilliardの回答 で説明されているように、文字列注釈を使用する必要があります。

Mypyは、Python 3.6で実行されている場合でも、前方宣言をすでにサポートしています。ただし、静的型チェッカーがコードに問題がないと言っても、インタープリターがNameError実際に実行しようとしたとき。


1.これは、 PEP 484 で可能な機能としてすでに説明されていますが、注釈で前方宣言を使用した経験が増えた後、後で延期されました。 PEP 563/Python3.7はその「後で」です。

6
abarnert

おそらく別の方法は、空の実装で以前にクラスを定義することです。最も一般的な解決策は 前方参照 だと思いますが、私の提案はよりタイプセーフであり、結局のところタイプを追加することを目的としています。

class Vector2:
    pass

class Vector2:

    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def Translate(self, pos: Vector2):
        self.x += pos.x
        self.y += pos.y
0
Ferran Maylinch