0

一部のデコレータは、最外層でのみ使用する必要があります。

元の関数を拡張し、configure パラメーターを追加するデコレーターはその一例です。

from functools import wraps

def special_case(f):
    @wraps(f)
    def _(a, b, config_x=False):
        if config_x:
           print "Special case here"
           return
        return f(a, b)

このようなデコレータが別のデコレータによって装飾されないようにするにはどうすればよいですか?

編集

新しいデコレータを適用しようとしているすべての人がアプリケーションの順序について心配するのは本当にうんざりです。

では、このような状況を回避することは可能でしょうか? 新しいパラメーターを導入せずに構成オプションを追加することは可能ですか?

4

2 に答える 2

5

飾るのを止める方法はありません。最後に適用する必要があることを文書化し、他のデコレーター内で使用しないように人々に伝える必要があります。

編集に対応する編集: Python 3 では、関数にキーワードのみの引数を与えることができます。これにより、関数の既存の使用に対する変更の影響が大幅に軽減されます。残念ながら、これは Python 3 でしか機能しません。

最終的に、デコレーターを関数に適用することは、装飾された関数を引数として別の関数に渡すことを意味します。関数 (または任意のオブジェクト) が、引数として渡されていることを知る方法さえありません。後のデコレータについて知ることができない理由は、 のような通常の関数呼び出しf(g(x))で、関数gが後で によって呼び出されることを知ることができないのと同じ理由ですf

これが、デコレータの記述が難しい理由の 1 つです。ラップされた関数に明示的な引数を渡すデコレーターの多用に依存するコード (あなたの関数が渡すaand などb) は、本質的に脆弱になります。幸いなことに、多くの場合、 and を使用するデコレーターを記述して、使用*args**kwargsないすべての引数を装飾された関数に渡すことができます。

誰かがあなたが提供したコードを受け取り、引数として and のみを明示的に受け入れる別のデコレーターを作成し、装飾された関数を as として呼び出したa場合、それが失敗した場合、それは彼ら自身の責任です。彼らは、使用した他のデコレータが関数のシグネチャを変更した可能性があることを知っていたはずです。bf(a, b, True)

于 2012-09-04T03:00:45.033 に答える
1

通常、一般的に使用されるデコレーターを作成する場合、ラップする関数の引数の数や名前を制限しません。

そこにあるほとんどのデコレーターは、位置引数のリストとキーワード引数のマッピングをラッパーのパラメーターとして受け入れ、受け取ったとおりに装飾された関数に渡します。

def deco(func):
   def wrapper(*args, **kwargs):
       ... decorator stuff here ...
       return func(*args, **kwargs)

したがって、デコレーターが「消費」する必要があるパラメーターを受け取る場合-config_xあなたが言及したように、それを文書化し、キーワードパラメーターとして使用し、から選択するだけですkwargs。パラメーターの名前の衝突を避けるために、たとえば、このパラメーター名の前にデコレーター自身の名前または他の個別の名前を付けることができます。

def deco(func):
   def wrapper(*args, **kwargs):
       if "deco_config_x" in kwargs):
           config_x = kwargs.pop(deco_config_x)
       ... decorator stuff here ...
       return func(*args, **kwargs)

このようにして、デコレータは「デコレータスタック」のどこにでも置くことができます - それはそれにアドレス指定されたパラメータを選択し、それ以下のものは奇妙なパラメータを取得しません。唯一の要件は、関数とデコレータ全体が突き抜けて、知らないキーワード パラメータが通過できるようにすることです。

于 2012-09-04T03:31:03.707 に答える