web-dev-qa-db-ja.com

Python 3.6の変数注釈とは何ですか?

Python 3.6がリリースされようとしています。 PEP 494-Python 3.6リリーススケジュール 12月の終わりについて言及しているので、私はこれに目を通しました Python 3.6の新機能 彼らが変数注釈に言及しているのを見てください:

PEP 484 関数パラメーターの型注釈に標準を導入、別名:型ヒント。このPEPは、クラス変数やインスタンス変数を含む変数のタイプに注釈を付けるための構文をPythonに追加します。

  primes: List[int] = []

  captain: str  # Note: no initial value!

  class Starship:
     stats: Dict[str, int] = {}

関数アノテーションと同様に、Pythonインタープリターは変数アノテーションに特定の意味を付加せず、クラスまたはモジュールの特別な属性__annotations__にのみ格納します。静的に型付けされた言語の変数宣言とは対照的に、注釈構文の目標は、抽象構文ツリーと__annotations__属性を介してサードパーティのツールとライブラリの構造化型メタデータを指定する簡単な方法を提供することです。

だから私が読んだことから、それらはPython 3.5から来るタイプヒントの一部です。これは Python 3.5のタイプヒントとは で説明されています。

captain: strclass Starshipの例に従いますが、最後の例についてはわかりません:primes: List[int] = []はどう説明しますか?整数だけを許可する空のリストを定義していますか?

58
fedorqui

:=の間はすべて型ヒントであるため、primesは実際にはList[int]として定義され、最初は空のリストに設定されます(そしてstatsは最初はDict[str, int]として定義される空の辞書です)。

List[int]Dict[str, int]は次の構文の一部ではありませんが、これらはPython 3.5タイピングヒントPEPで既に定義されています。 3.6 PEP 526 –変数注釈の構文 提案onlyは、同じヒントを付加する構文を定義します。変数へ;型ヒントを変数にコメントのみ添付する前に(例:primes = [] # List[int])。

ListDictはどちらもGenericタイプであり、特定の(具体的な)コンテンツを持つリストまたは辞書マッピングがあることを示します。

Listには、リスト内のすべての要素の型である「引数」([...]構文の要素)のみがあります。 Dictの場合、最初の引数はキータイプで、2番目は値タイプです。したがって、primesリストのall値は整数であり、stats辞書のallキーと値のペアは(str, int)のペアであり、文字列をマッピングします整数に。

typing.List および typing.Dict の定義、 Generics のセクション、および- PEP 483 –タイプヒントの理論

関数の型ヒントと同様に、それらの使用はオプションであり、注釈とも見なされます(これらを添付するオブジェクトがある場合、モジュールのグローバルとクラスの属性はローカルではありません) __annotations__属性を介してイントロスペクトできます。これらの注釈には任意の情報を添付できますが、タイプヒント情報に厳密に限定されるわけではありません。

完全な提案 ;を読むこともできます。新しい構文を超えた追加機能が含まれています。そのような注釈が評価されるタイミング、それらを内省する方法、およびクラス属性対インスタンス属性として何かを宣言する方法などを指定します。

34
Martijn Pieters

変数注釈とは何ですか?

変数注釈は、# typeで定義されているように、PEP 484コメントの次のステップにすぎません。この変更の理由は、 PEP 526の各セクション で強調されています。

したがって、タイプを次のようにヒントする代わりに:

primes = []  # type: List[int]

新しい構文が導入されました、フォームの割り当てで型に直接注釈を付けることができます:

primes: List[int] = []

@Martijnが指摘したように、これは typing で使用可能な型を使用して整数のリストを示し、空のリストに初期化します。

それはどんな変化をもたらしますか?

最初に導入された変更は 新しい構文 でした。これにより、名前を型で注釈することができ、:文字の後にスタンドアロンで、またはオプションで値を割り当てながら注釈を付けることができます。

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

したがって、問題の例:

   primes: List[int] = [ ]
#    ^        ^         ^
#  augtarget  |         |
#         expression    |
#                  expression (optionally initialize to empty list)

新しい構文とともに追加の変更も導入されました。モジュールとクラスには__annotations__属性があります(関数がから持っていたように(= /// =) PEP 3107-Function Annotations):タイプメタデータが添付されます:

from typing import get_type_hints  # grabs __annotations__

これで__main__.__annotations__には宣言された型が保持されます。

>>> from typing import List, get_type_hints
>>> primes: List[int] = []
>>> captain: str
>>> import __main__
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int]}

captainは現在、 get_type_hints を介して表示されません。これは、get_type_hintsがモジュール上でもアクセスできる型のみを返すためです。つまり、最初に値が必要です:

>>> captain = "Picard"
>>> get_type_hints(__main__)
{'primes': typing.List<~T>[int], 'captain': <class 'str'>}

print(__annotations__)を使用すると'captain': <class 'str'>が表示されますが、実際に__annotations__に直接アクセスするべきではありません。

同様に、クラスの場合:

>>> get_type_hints(Starship)
ChainMap({'stats': typing.Dict<~KT, ~VT>[str, int]}, {})

ChainMapを使用して、特定のクラス(最初のマッピングにある)の注釈と、mroにある基本クラスで定義されているすべての注釈(その後のマッピング、オブジェクトの{})を取得します。

新しい構文とともに、クラス変数を示す新しい ClassVar タイプが追加されました。うん、あなたの例のstatsは実際にはインスタンス変数であり、ClassVarではありません。

それを使用せざるをえませんか?

PEP 484の型ヒントと同様に、これらは完全にオプションであり、型チェックツールで主に使用されます(および、この情報に基づいて構築できるその他のもの)。 Python 3.6の安定バージョンがリリースされたときに暫定的なものになるため、将来的に小さな調整が追加される可能性があります。