Python 3.5
で話題になっている機能の1つはtype hints
と言われています。
type hints
の例は、この 記事 と この にもあります責任を持って型ヒントを使用する。誰かがそれについてそしてそれがいつ使用されるべきで、いつ使用されないのかについてもっと説明することができますか?
PEP 483 と PEP 484 を読んで、 this TypeでのGuidoのプレゼンテーションを見ることをお勧めします。ヒント。
一言で言えば:タイプヒントは文字通り言葉の意味であり、使用しているオブジェクトのタイプを示唆します。
Pythonの動的の性質により、使用中のオブジェクトのタイプの推測またはチェックは特に困難です。この事実は、開発者が自分が書いていないコードで何が起こっているのかを正確に理解することを難しくします。最も重要なことは、多くのIDE [PyCharm、PyDevオブジェクトのタイプを示すインジケータはありません。その結果、彼らは(プレゼンテーションで述べたように)約50%の成功率でタイプを推測しようとしています。
Type Hintingプレゼンテーションから2つの重要なスライドを取得するには:
TypeErrors
を取得せずに、どこで、どのように使用するかを知っています。.
を押して、オブジェクトに対して定義されていないメソッド/属性がポップアップ表示されることでしょう。この小さな紹介の最後のメモとして:これはoptional機能ですそして、私が理解していることから、静的型付けのいくつかの利点を享受するために導入されました。
通常、しないでくださいそれについて心配する必要はなく、明確にしないでくださいそれを使用する必要があります(特に補助スクリプト言語としてPythonを使用する場合)。として大規模なプロジェクトを開発する場合に役立ちます。これは、非常に必要な堅牢性、制御、および追加のデバッグ機能を提供します。
この回答をより完全なものにするために、ちょっとしたデモンストレーションが適していると思います。 mypy
を使用します。これは、PEPに表示されるTypeヒントを刺激したライブラリです。これは主に、この質問にぶつかり、どこから始めるべきか疑問に思う人のために書かれています。
その前に、次のことを繰り返してみましょう。 PEP 484 は何も強制しません。関数の注釈の方向を設定し、how型チェックを実行できるかどうかのガイドラインを提案するだけです。関数に注釈を付けて、好きなだけヒントを付けることができます。 Python自体はそれらを使用しないため、注釈の有無にかかわらずスクリプトは引き続き実行されます。
とにかく、PEPに記載されているように、ヒントの種類は一般に3つの形式を取る必要があります。
# type: type
コメント。 (参照:Python 3.6の変数注釈とは?Python 3.6 # type: type
コメントの更新)さらに、Py3.5
で導入された新しい typing
モジュールと組み合わせて、タイプヒントを使用することもできます。その中で、多くの(追加の)ABC(抽象基本クラス)が、静的チェックで使用するヘルパー関数とデコレーターと共に定義されています。 collections.abc
のほとんどのABCs
は含まれていますが、サブスクリプションを許可するためにGeneric
形式になっています(__getitem__()
メソッドを定義することにより)。
これらのより詳細な説明に興味がある人のために、 mypy documentation
は非常にうまく書かれており、チェッカーの機能を実証/説明する多くのコードサンプルがあります。それは間違いなく読む価値があります。
まず、特別なコメントを使用した場合に得られるいくつかの動作を観察するのは興味深いことです。特別な# type: type
コメントを変数の割り当て中に追加して、オブジェクトを直接推測できない場合にオブジェクトのタイプを示すことができます。通常、単純な割り当ては簡単に推測できますが、リストのような他のもの(内容に関して)は推測できません。
注:Containers
の派生物を使用し、そのコンテナの内容を指定する必要がある場合は、musttyping
モジュールのジェネリックタイプを使用します。 これらはインデックス作成をサポートしています。
# generic List, supports indexing.
from typing import List
# In this case, the type is easily inferred as type: int.
i = 0
# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = [] # type: List[str]
# Appending an int to our list
# is statically not correct.
a.append(i)
# Appending a string is fine.
a.append("i")
print(a) # [0, 'i']
これらのコマンドをファイルに追加してインタープリターで実行すると、すべて正常に機能し、print(a)
はリストa
の内容を出力するだけです。 # type
コメントは破棄されました。追加のセマンティックな意味を持たない単純なコメントとして扱われます。
一方、これをmypy
で実行すると、次の応答が得られます。
(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
str
オブジェクトのリストにint
を含めることはできません。これは静的に言えば健全です。これは、a
のタイプに準拠してstr
オブジェクトのみを追加するか、a
のコンテンツのタイプを変更して、値が受け入れられることを示すことで修正できます(Any
がtyping
からインポートされた後、List[Any]
で直感的に実行されます)。
関数アノテーションは、関数シグネチャの各パラメーターの後にparam_name : type
という形式で追加され、終了関数コロンの前に-> type
表記を使用して戻り値の型が指定されます。すべての注釈は、便利な辞書形式でその関数の__annotations__
属性に格納されます。簡単な例を使用します(これはtyping
モジュールからの追加の型を必要としません):
def annotated(x: int, y: str) -> bool:
return x < y
annotated.__annotations__
属性の値は次のとおりです。
{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
私たちが完全な初心者である場合、またはPy2.7
の概念に精通しており、その結果TypeError
の比較に潜むannotated
に気付いていない場合は、別の静的チェックを実行してエラーをキャッチし、トラブルを回避できます。
(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")
とりわけ、無効な引数で関数を呼び出すこともキャッチされます:
annotated(20, 20)
# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"
これらは基本的にどのようなユースケースにも拡張でき、キャッチされるエラーは基本的な呼び出しや操作よりも拡張されます。確認できるタイプは非常に柔軟であり、その可能性の小さなピークを示しただけです。 typing
モジュール、PEP、またはmypy
ドキュメントを参照すると、提供される機能のより包括的な概念がわかります。
スタブファイルは、相互に排他的な2つの異なるケースで使用できます。
スタブファイル(拡張子.pyi
)は、作成/使用するモジュールの注釈付きインターフェイスです。これらには、型チェックする関数のシグネチャが含まれ、関数の本体は破棄されます。 randfunc.py
という名前のモジュールに3つのランダム関数のセットが与えられた場合、これを感じるために:
def message(s):
print(s)
def alterContents(myIterable):
return [i for i in myIterable if i % 2 == 0]
def combine(messageFunc, itFunc):
messageFunc("Printing the Iterable")
a = alterContents(range(1, 20))
return set(a)
スタブファイルrandfunc.pyi
を作成できます。作成したい場合は、いくつかの制限を設定できます。欠点は、スタブなしでソースを表示している人が、どこで何が渡されるべきかを理解しようとするときに、実際にその注釈の支援を得られないことです。
とにかく、スタブファイルの構造は非常に単純です。すべての関数定義に空のボディ(pass
が入力されている)を追加し、要件に基づいて注釈を指定します。ここでは、コンテナに対してint
型のみを使用したいと仮定します。
# Stub for randfucn.py
from typing import Iterable, List, Set, Callable
def message(s: str) -> None: pass
def alterContents(myIterable: Iterable[int])-> List[int]: pass
def combine(
messageFunc: Callable[[str], Any],
itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass
combine
関数は、別のファイルで注釈を使用する理由を示しますが、コードが乱雑になり読みやすさが低下する場合があります(Pythonにとっては大きな問題です)。もちろん、タイプエイリアスを使用することもできますが、それが役立つ以上に混乱することがあります(そのため、それらを賢く使用してください)。
これにより、PythonのType Hintsの基本概念を理解できるはずです。使用されている型チェッカーはmypy
でしたが、徐々に多くのポップアップが表示されるようになるはずです。一部はIDEの内部( PyCharm 、)およびその他の標準pythonモジュールとして。それらが見つかった場合(または提案された場合)は、次のリストにチェッカー/関連パッケージを追加してみます。
私が知っているチェッカー:
関連パッケージ/プロジェクト:
typeshed
プロジェクトは、実際に、独自のプロジェクトで型ヒントがどのように使用されるかを確認するのに最適な場所の1つです。例として、 対応する__init__
ファイル内のCounter
class の.pyi
dundersを見てみましょう。
class Counter(Dict[_T, int], Generic[_T]):
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
@overload
def __init__(self, iterable: Iterable[_T]) -> None: ...
__T = TypeVar('_T')
を使用して、汎用クラス を定義します。 Counter
クラスの場合、イニシャライザで引数を取らないか、任意の型から単一のMapping
を取得してint
またはを取得して、任意の型のIterable
を取得できることがわかります。
Notice:私が言及するのを忘れていた1つのことは、typing
モジュールが暫定ベースで導入されたことです。 FromPEP 411:
暫定パッケージのAPIは、「卒業」して「安定」状態になる前に変更される場合があります。一方で、この状態はパッケージにPythonディストリビューションの正式な一部であるという利点を提供します。一方、コア開発チームは、パッケージのAPIの安定性に関しては約束されていないと明示的に述べており、次のリリースで変更される可能性があります。ありそうもない結果と見なされますが、そのようなパッケージは、APIまたはメンテナンスに関する懸念が十分に根拠があると判明した場合、廃止期間なしに標準ライブラリから削除されることさえあります。
塩を少し入れて、ここに物を置いてください。かなりの方法で削除または変更されるとは思いますが、知ることはできません。
** 完全に別のトピックですが、タイプヒントの範囲で有効です: PEP 526
:Variable Annotations の構文は、ユーザーが変数のタイプに注釈を付けることができる新しい構文を導入することで# type
コメントを置き換える努力です単純なvarname: type
ステートメントで。
を参照してくださいPython 3.6の変数注釈とは?、前述のように、これらの小さなイントロについて。
ジムの巧妙な答えに加えて:
typing
モジュール を確認してください - このモジュールは で指定されている型のヒントをサポートしていますPEP 484 .
たとえば、以下の関数はstr
型の値を取得して返し、次のように注釈が付けられています。
def greeting(name: str) -> str:
return 'Hello ' + name
typing
モジュールは以下もサポートします。
新しくリリースされたPyCharm 5はタイプヒントをサポートします。それについての彼らのブログ記事で( PyCharm 5の中のPython 3.5型ヒント - を見てください )彼らはどんな型ヒントがあるかどうかについての素晴らしい説明を使い方のいくつかの例と実例と共に提供しますあなたのコードでそれらを。
さらに、 このコメントで説明されているように、Python 2.7でもサポートされています :
PyCharmはPython 2.7用のPyPI、Python 3.2-3.4からの型付けモジュールをサポートします。 2.7では、関数アノテーションがPython 3.0で追加されたので、*。pyiスタブファイルに型のヒントを入れる必要があります。