Python 3.5で最も話題になっている機能の1つは型ヒントです。
型ヒントの例はこの記事とこの記事で説明されていますが、責任を持って型ヒントを使用することについても言及されています。誰かがそれらについて、それらをいつ使用すべきか、いつ使用すべきかについて説明できますか?
Python 3.5で最も話題になっている機能の1つは型ヒントです。
型ヒントの例はこの記事とこの記事で説明されていますが、責任を持って型ヒントを使用することについても言及されています。誰かがそれらについて、それらをいつ使用すべきか、いつ使用すべきかについて説明できますか?
回答:
PEP 483とPEP 484を読んで、タイプヒンティングに関するGuidoによるこのプレゼンテーションを見ることをお勧めします。
一言で言えば:タイプヒンティングは、文字通り言葉が何を意味するか、あなたが使用しているオブジェクト(複数可)のタイプをヒントです。
Python の動的な性質により、使用されているオブジェクトのタイプを推測またはチェックすることは特に困難です。この事実により、開発者は自分が記述していないコードで何が起こっているのかを正確に理解することが難しくなり、最も重要なのは、多くのIDEにある型チェックツール[PyCharm、PyDevが頭に浮かぶ]が原因で制限されているためです。オブジェクトのタイプを示すインジケータはありません。その結果、彼らは(プレゼンテーションで述べたように)約50%の成功率で型を推測しようとしています。
タイプヒントプレゼンテーションから2つの重要なスライドを取得するには:
TypeErrors
。.
した可能性があり、オブジェクトに定義されていないメソッド/属性ポップアップが表示されます。この小さな紹介の締めくくりとして、これはオプションの機能であり、私が理解しているところから、静的型付けのいくつかの利点を享受するために紹介されました。
あなたは、一般的にはありませんそれを心配する必要があると間違いなく(特にあなたが補助スクリプト言語としてPythonを使用する場合には)それを使用する必要はありません。非常に必要な堅牢性、制御、および追加のデバッグ機能を提供するため、大規模なプロジェクトを開発するときに役立ちます。
この回答をより完全にするために、少しデモンストレーションが適切だと思います。mypy
PEPで提示されているタイプヒントに影響を与えたライブラリであるを使用します。これは主に、この質問にぶつかり、どこから始めればよいか迷っている人のために書かれています。
私は前にそれは私が次のことをあらためて表明しましょう:PEP 484には何も強制しません。それは単に関数注釈の方向を設定し、型チェックをどのように実行できる/すべきかについてのガイドラインを提案することです。関数に注釈を付けたり、好きなだけヒントを与えたりすることができます。Python自体は注釈を使用しないため、注釈の存在に関係なくスクリプトは実行されます。
とにかく、PEPに記載されているように、ヒントタイプは一般に次の3つの形式を取ります。
# type: type
最初の2つの形式を補足する特別なコメント。(コメント:Python 3.6アップデートのコメントについては、Python 3.6の変数アノテーションとは何ですか?# type: type
)さらに、でtyping
導入された新しいモジュールと共に型ヒントを使用する必要がありますPy3.5
。その中で、多くの(追加の)ABC(Abstract Base Classes)が、静的チェックで使用するヘルパー関数とデコレーターとともに定義されています。ほとんどが含まABCs
れcollections.abc
ていますが、Generic
(__getitem__()
メソッドを定義することにより)サブスクリプションを許可するためのフォームに含まれています。
これらのより詳細な説明に興味がある人のために、これmypy documentation
は非常にうまく書かれており、チェッカーの機能を実証/説明する多くのコードサンプルがあります。それは間違いなく読む価値があります。
まず、特別なコメントを使用したときに発生する可能性のある動作を観察するのは興味深いことです。# type: type
変数を割り当てるときに特別なコメントを追加して、オブジェクトを直接推論できない場合にオブジェクトのタイプを示すことができます。単純な割り当ては一般に簡単に推測できますが、リストなど(内容に関して)は割り当てられません。
注:の派生物を使用しContainers
、そのコンテナーのコンテンツを指定する必要がある場合は、モジュールのジェネリック型を使用する必要がありtyping
ます。これらはインデックス作成をサポートします。
# 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)
、listの内容を出力します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
任意の値が受け入れ可能であることを示すことで修正できます(からインポートしたList[Any]
後、で直感的に実行)。Any
typing
関数の注釈は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
)とは、作成または使用したいモジュールの注釈付きインターフェースです。それらには、型チェックしたい関数のシグニチャーが含まれ、関数の本体は破棄されます。これの感触を得るために、という名前のモジュールで3つのランダム関数のセットが与えられたとしますrandfunc.py
。
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のタイプヒントの基本概念に慣れるはずです。使用されている型チェッカーが使用されているmypy
場合でも、徐々にそれらのポップアップの表示を開始する必要があり
ます。一部は内部でIDE(PyCharm)に、その他は標準のPythonモジュールとして表示されます。見つかった場合(または提案された場合)、チェッカーや関連パッケージを次のリストに追加してみます。
私が知っているチェッカー:
関連パッケージ/プロジェクト:
typeshed
このプロジェクトは、実際にあなたがタイプヒンティングは、あなた自身のプロジェクトで使用されるかもしれない方法を確認するために見ることができる最高の場所の一つです。例として、対応するファイル内のクラスの__init__
ダンダーをCounter
見てみましょう.pyi
。
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
あらゆる種類の。
注意:私が言及し忘れたことの1つは、typing
モジュールが暫定的に導入されたことです。PEP 411から:
暫定パッケージは、「安定」状態に「段階的に」変化する前に、APIが変更されている場合があります。一方で、この状態は正式にPythonディストリビューションの一部であるという利点をパッケージに提供します。一方、コア開発チームは、パッケージのAPIの安定性に関しては何の約束もなされないことを明言しており、次のリリースで変更される可能性があります。ありそうもない結果と考えられていますが、そのようなパッケージは、APIまたはメンテナンスに関する懸念が根拠があることが判明した場合、非推奨期間なしで標準ライブラリから削除されることさえあります。
塩を少し入れて、ここに物を置いてください。私はそれがかなりの方法で削除または変更されるかどうか疑わしいですが、誰も知ることができません。
**型のヒントの範囲内の別の完全な話題が、有効な:PEP 526
:構文変数注釈については、置き換えるための努力で# 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は、PyPI for Python 2.7、Python 3.2-3.4の型付けモジュールをサポートしています。2.7では、関数の注釈がPython 3.0で追加されたため、*。pyiスタブファイルに型ヒントを配置する必要があります。
タイプヒントは動的言語に最近追加されたもので、何十年もの間、ハンガリー語のように単純な命名規則を採用していました(最初の文字がb =ブーリアン、c =文字、d =辞書、i =整数、l =リスト、n =数値のオブジェクトラベル) 、s =文字列、t =タプル)は不要であり、面倒でしたが、今や決定しました、待ってください...言語(type())を使用してオブジェクトを認識するのは非常に面倒で、私たちの豪華なIDE複雑な処理を行う必要があり、動的に割り当てられたオブジェクトの値はとにかくまったく役に立たないのに対し、単純な命名規則では、開発者は一目ですべてを解決できた可能性があります。
タイプヒントは保守性のためのものであり、Pythonによって解釈されません。以下のコードでは、その行def add(self, ic:int)
は次のreturn...
行までエラーになりません。
class C1:
def __init__(self):
self.idn = 1
def add(self, ic: int):
return self.idn + ic
c1 = C1()
c1.add(2)
c1.add(c1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'