web-dev-qa-db-ja.com

Python 3および静的型付け

私はPython 3の開発に私が望んでいたほど多くの注意を払わず、興味深い新しい構文の変更に気付いただけです。具体的には thisからSO answer 関数パラメーターアノテーション:

def digits(x:'nonnegative number') -> "yields number's digits":
    # ...

これについて何も知らないので、Pythonで静的型付けを実装するために使用できると思いました!

いくつかの検索の後、 PEP 3107 および "Pythonへのオプションの静的型付けの追加" (および part 2

..しかし、これがどこまで進んだのかはわかりません。パラメーター注釈を使用した静的型付けの実装はありますか?パラメーター化されたタイプのアイデアのいずれかがPython 3?

57
dbr

コードを読んでくれてありがとう!

実際、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 __== '__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???

人間は変数heightlengthの 'human type'を知っていれば、上の行の間違いをすぐに見るはずです(コンピューターはに見えますが) intfloatの完全に合法的乗算。

この問題の可能な解決策について言えることは他にもありますが、「コンピューターの種類」を適用することは明らかに半分の解決策であるため、少なくとも私の意見では、まったく解決策がないです。 Systems Hungarianがひどい考えであるのと同じ理由です(Apps Hungarian素晴らしいものです。非常に情報量の多いJoel Spolskyの投稿です。

誰かが実際のデータにそのhuman typeを自動的に割り当てる何らかの種類のPythonicサードパーティライブラリを実装する場合、変換に注意してくださいwidth * height -> areaのようなタイプで、関数の注釈を使用してそのチェックを強制すると、それは人々が本当に使用できるタイプチェックになると思います。

33
ilya n.

そのPEPで述べたように、静的型チェックは機能注釈を使用できるアプリケーションの1つですが、その方法を決定するためにサードパーティのライブラリに任せています。つまり、コアPythonには公式の実装はありません。

サードパーティの実装に関する限り、いくつかのスニペット( http://code.activestate.com/recipes/572161/ など)があり、これはかなりうまく機能しているようです。

編集:

注として、型のチェックよりも振る舞いのチェックの方が望ましいことを述べたいと思うので、静的型チェックはそれほど素晴らしいアイデアではないと思います。上記の私の答えは、質問に答えることを目的としています。そのような方法で自分で型チェックを行うからではありません。

14
sykora

これは直接質問への答えではありませんが、静的な型付けを追加するPythonフォークを見つけました: mypy-lang.org 、もちろん信頼できませんそれはまだ小さな努力ですが、興味深いものです。

13
Ciantic

Pythonの "静的型付け"は、実行時に型チェックが行われるようにのみ実装できます。つまり、アプリケーションの速度が低下します。したがって、一般性としては望ましくありません。代わりに、いくつかのメソッドで入力をチェックする必要がありますが、これは単純なアサートで、または(誤って)必要だと思われる場合はデコレータで簡単に実行できます。

静的型チェックの代替手段もあります。これは、Zopeコンポーネントアーキテクチャのようなアスペクト指向のコンポーネントアーキテクチャを使用することです。タイプをチェックする代わりに、それを適応させます。代わりに:

assert isinstance(theobject, myclass)

これをして:

theobject = IMyClass(theobject)

オブジェクトがすでにIMyClassを実装している場合、何も起こりません。そうでない場合は、オブジェクトがIMyClassにラップされているアダプタが検索され、オブジェクトの代わりに使用されます。アダプタが見つからない場合、エラーが発生します。

これは、Python)のダイナミズムと、特定の方法で特定のタイプを使用したいという願望を組み合わせたものです。

12
Lennart Regebro

確かに、静的な型付けは少し "unpythonic"のようで、私は常にそれを使用しません。ただし、開発を実際にスピードアップできる場合(ドメイン固有の言語解析など、ネストされたクラスなど)があります。

それから beartype をこの post *で説明することを好む。 gitリポジトリ、テスト、およびそれができることとできないことの説明が付属しています...そして、私は名前が好きです;)

*なぜPythonにはこのケースにバッテリーが付属していませんか?.

0
Iwan LD