1

モジュール内の各関数の引数のタイプを確認したいと思います(inspectモジュールを使用せずに)。私が自分で行った最も簡単な解決策は、各関数に個別にチェックを実装することです。

def func1( num1, num2 ):  # the two params must be integers
    if isinstance( num1, int ) and isinstance( num2, int ):
        # ...function code...
        pass
    else:
        return

def func2( float1 ):  # The only param must be float

    if isinstance( float1, float ):
        # ...function code...
        pass
    else:
        return

def func3( str1 ):  # string
    if isinstance( str1, str ):
        # ...function code...
        print 'fdfd'
        pass
    else:
        return


# and, so on ...

ただし、関数ごとに実行するのではなく、モジュールレベルで実行する必要があります。各関数は異なる引数を持つことができます。これは関数のオーバーロードではないことに注意してください。デコレータかメタクラスのどちらかを書くことを考えていました。これが私が両方のアプローチで直面した問題です:-

  1. すべての関数に共通のデコレータを使用する:
    この方法では、各関数内で定義されている実際の変数にアクセスできないため、このアイデアを破棄しました。これが私が書くことを計画していたクロージャー(デコレーターとして使用される)です:
def dec( funcName ):
    def typeChecker():
        i = __import__( __name__ )
        for m in map( lambda x: i.__getattribute__( x ), dir( i ) ):
            if '__call__' in dir( m ):  #Identifying a real function or callable which can be treated as function
                ## Now, that the function is identified, what should I do here to type-check the arguments??
    return typeChecker

私がこれをどのように機能させることができるかについて、ここでいくつかの洞察を提供してください。

2.関数の作成にメタクラスを
使用するメタクラスを使用して関数に送信される引数にアクセスし、各引数を検証してから、作成を担当する新しいクラスを返すことができるかどうか疑問に思っていました。関数オブジェクト。しかし、それを行う方法がわかりません。この問題を解決する良い方法ですか?

MartijnPetersが与えた1つの非常に良い提案-注釈を使用する。Python 2.7に使用できるものはありますか?

4

2 に答える 2

1

デコレーターを介してこれを行うのはかなり簡単です。Python 2 では、各関数を明示的に装飾して、各パラメーターの型に注釈を付ける必要があります。または、doc-string にマークアップを使用して注釈を使用し、モジュール上のすべてのオブジェクトを反復処理し、その中で定義された各関数にデコレータを適用します。

どちらの場合も、次のようなデコレータで十分です。

from functools import wraps
from itertools import count

def typechecker(*types, **kw_types):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kw):
            for position, type_, arg in zip(count(), types, args):
                if not isinstance(arg, type_):
                    raise TypeError("Argument in position %s should be a %s"
                                    % (position, type_))
            for key, type_ in kw_types.items():
                if key in kw_types and not isinstance(kw[key], type_):
                    raise TypeError("Argument %s should be a %s"
                                    % (key, type_))
            return func(*args, **kw)
        return wrapper
    return decorator

そして、次のように動作することがわかります。

>>> @typechecker(int, int)
... def mysum(a,b):
...    return a + b
... 
>>> mysum(2,3)
5
>>> mysum(2.0,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in wrapper
TypeError: Argument in position 0 should be a <type 'int'>
>>> 
于 2013-04-01T11:04:13.577 に答える
-1

私の傾向は次のようになります。

class A(object):
    def func(self, arg):
        result = self._get_func(arg)(arg)

    def _get_func(self, arg):
        # Create and return the appropriate function here.
        # You have a variety of options, e.g. arg.__class__ (if it exists),
        # or use a bunch of isinstance checks, etc.
        # Please bear in mind that this is really unpythonic!!
        if isinstance(arg, basestring):
            pass

関数を頻繁に呼び出す場合、これは明らかに非効率的であるため、特定の関数をキャッシュし、最初に 内でキャッシュからプルしようとします_get_func

def _get_func(self, arg):
    if arg.__class__ in self._cache: # Or whatever
        return self._cache[arg.__class__]
    else:
        pass # Create and return the appropriate function here.

もちろん_get_func、必要に応じてメソッドをオーバーライドできます (これは、モジュール レベルまたはクラス レベルで機能するはずですが、明確にするためにクラスを好むでしょう)。

また、これは本当に非pythonicであることにも言及する価値があります。関数コンストラクター内にそれらを隠すのではなく、別のことを行う必要がある場合は、別の関数をオープンに記述する方が一般的にははるかにクリーンです。または、少なくとも「許しを請う方が良い」try/exceptブロックを使用して、特定のタイプ/クラスにのみ適用される操作をカプセル化します。

于 2013-03-19T19:45:36.900 に答える