Python 3 と静的型付け
-
16-09-2019 - |
質問
私は Python 3 の開発には思ったほど注意を払っておらず、興味深い新しい構文の変更に気づいただけでした。具体的には このSOの答え 関数パラメータの注釈:
def digits(x:'nonnegative number') -> "yields number's digits":
# ...
これについては何も知らなかったので、Python で静的型付けを実装するために使用できるのではないかと考えました。
いくつか検索した結果、Python での (完全にオプションの) 静的型付けについては多くの議論があるようでした。 PEP 3107, 、 そして 「オプションの静的型付けを Python に追加する」 (そして パート2)
……しかし、どこまで進んだのかは分かりません。パラメータアノテーションを使用した静的型付けの実装はありますか?パラメータ化されたタイプのアイデアは Python 3 に取り入れられましたか?
解決
私のコードを読んでいただきありがとうございます!
実際、Python で汎用のアノテーション エンフォーサを作成するのは難しくありません。私の見解は次のとおりです。
'''Very simple enforcer of type annotations.
This toy super-decorator can decorate all functions in a given module that have
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.
This module also has a test function func() which should fail and logging facility
log which defaults to print.
Since this is a test module, I cut corners by only checking *keyword* arguments.
'''
import sys
log = print
def func(x:'int' = 0) -> 'str':
'''An example function that fails type checking.'''
return x
# For simplicity, I only do keyword args.
def check_type(*args):
param, value, assert_type = args
log('Checking {0} = {1} of {2}.'.format(*args))
if not isinstance(value, assert_type):
raise AssertionError(
'Check failed - parameter {0} = {1} not {2}.'
.format(*args))
return value
def decorate_func(func):
def newf(*args, **kwargs):
for k, v in kwargs.items():
check_type(k, v, ann[k])
return check_type('<return_value>', func(*args, **kwargs), ann['return'])
ann = {k: eval(v) for k, v in func.__annotations__.items()}
newf.__doc__ = func.__doc__
newf.__type_checked = True
return newf
def decorate_module(module = '__main__'):
'''Enforces type from annotation for all functions in module.'''
d = sys.modules[module].__dict__
for k, f in d.items():
if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
log('Decorated {0!r}.'.format(f.__name__))
d[k] = decorate_func(f)
if __name__ == '__main__':
decorate_module()
# This will raise AssertionError.
func(x = 5)
この単純さを考えると、これが主流ではないのは一見すると奇妙です。ただし、それには十分な理由があると私は信じています 見た目ほど役に立たない. 。一般に、整数と辞書を追加すると、明らかな間違いを犯した可能性が高いため、型チェックが役に立ちます (また、妥当なことを意味しているとしても、それは依然として間違いです)。 暗黙的よりも明示的である方がよい).
しかし、現実の生活では、同じ量のものを混ぜることがよくあります。 コンピュータの種類 コンパイラで見た通りだが明らかに違う 人間タイプ, たとえば、次のスニペットには明らかな間違いが含まれています。
height = 1.75 # Bob's height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What's that supposed to mean???
変数の「人間型」を知っていれば、誰でも上記の行の間違いにすぐに気づくはずです。 height
そして length
コンピュータからは次のように見えますが、 完全に合法 の乗算 int
そして float
.
この問題の可能な解決策について言えることはまだありますが、「コンピュータの種類」を強制することは明らかに半分の解決策であるため、少なくとも私の意見では、 まったく解決策がないより悪い. 。それも同じ理由です ハンガリー語システム それはひどい考えですが、 ハンガリー語のアプリ 素晴らしいものです。非常に有益な情報がさらにあります ジョエル・スポルスキーのポスト.
ここで、誰かが現実世界のデータに自動的に割り当てるある種の Pythonic サードパーティ ライブラリを実装したとします。 人間タイプ そして、その型を次のように変換することに注意しました width * height -> area
関数アノテーションを使用してそのチェックを強制すると、これは人々が実際に使用できる型チェックになると思います。
他のヒント
、静的型チェックは注釈がために使用することができる機能の可能なアプリケーションの一つであるが、彼らはそれを行う方法を決定するために、サードパーティのライブラリにそれを残しています。つまり、コアPythonで公式の実装があるように行くのではありません。
//:は、限り、サードパーティの実装が懸念しているとして、そのような HTTPなどのいくつかのスニペット(がありますcode.activestate.com/recipes/572161/ に)、かなりよく仕事をするように見えるれます。
EDITます:
注意点として、私はので、私は、静的型チェックはそれほど素晴らしいアイデアではないと思い、行動をチェックするタイプのチェックに好適であることを言及したいと思います。上記の質問に答えることを目的としている私の答えは、私は、このような方法で自分自身を型チェックするだろうではないので。
この直接質問への答えではありませんが、私は静的型付けを追加するPythonのフォークを見つけた: mypy-それはまだ小さな努力が、面白いようlang.org に、もちろん一つはそれに頼ることはできません。
「静的型付けは、」だけではアプリケーションが遅くなることを意味する、実装することができます。したがって、あなたは一般性としてそれを望んでいません。代わりに、あなたはあなたの方法のいくつかは、それの入力をチェックしたいです。あなたは(誤って)あなたはそれをたくさん必要だと思う場合、これは簡単に無地でアサート行われ、あるいはデコレータを持つことができます。
があり、静的型チェックの代替でもあり、それはZopeのコンポーネントアーキテクチャのようアスペクト指向コンポーネント・アーキテクチャーを使用することです。代わりにタイプをチェックし、あなたはそれを適応させます。だから、代わりに:
assert isinstance(theobject, myclass)
あなたはこれを行います
theobject = IMyClass(theobject)
theobjectはすでにIMyClassを実装している場合は、何も起こりません。そうでない場合は、IMyClassにあるものは何でもtheobjectラップアダプタを見上げて、代わりにtheobjectのに使用されます。何のアダプターが見つからない場合は、エラーを取得します。
これは、特定の方法で特定のタイプを持っている願望でのPythonのdynamicismを合わせます。