61

私は Python 3 の開発にあまり注意を払っていませんでしたが、興味深い新しい構文の変更に気付いただけでした。具体的には、この SO 回答関数パラメーターの注釈から:

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

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

いくつかの検索の後、 PEP 3107で言及されているものや、「Adding Optional Static Typing to Python」 (およびパート 2 )など、Python での (完全にオプションの) 静的型付けに関して多くの議論があったようです。

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

4

5 に答える 5

35

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

実際、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見えても、上記の行の間違いにすぐに気付くはずです。intfloat

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

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

于 2009-08-14T07:53:55.743 に答える
15

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

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

編集:

注意として、振る舞いをチェックすることは型をチェックすることよりも好ましいということを述べたいと思います。したがって、静的な型チェックはあまり良い考えではないと思います。上記の私の答えは、そのような方法で自分自身をタイプチェックするからではなく、質問に答えることを目的としています。

于 2009-08-14T01:53:23.803 に答える
14

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

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

assert isinstance(theobject, myclass)

これをして:

theobject = IMyClass(theobject)

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

これにより、Python のダイナミズムと、特定の型を特定の方法で取得したいという欲求が組み合わされました。

于 2009-08-14T05:01:33.390 に答える
13

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

于 2013-02-11T15:05:33.347 に答える
0

確かに、静的型付けは少し「非 Pythonic」に思えますが、私は常にそれを使用しているわけではありません。しかし、場合によっては (ドメイン固有言語の構文解析のように入れ子になったクラスなど)、実際に開発をスピードアップできる場合もあります。

次に、この投稿で説明されているベアタイプを使用することをお勧めします*。git レポジトリ、テスト、何ができて何ができないかの説明が付属しています...そして私はその名前が好きです ;)

* この場合、Python に電池が付属していない理由についての Cecil の暴言に注意を払わないでください。

于 2016-08-25T12:44:30.970 に答える