1


0

私はデコレータがあります:

Functoolsのインポートからdef d(f)をラップします。

そして私はそれが同じ機能を二度飾るのを防ぎたい。

@ d @ d def f():印刷2

私が考えることができる唯一の可能な解決策はデコレータがすでに装飾した機能を格納するために辞書を使用し、辞書に存在する機能を装飾するように頼まれた場合例外を発生させることです。 もっと良いアイデアがあるかどうか教えてください…​

4 Answer


2


関数自体に情報を格納します。 複数のデコレータが同じ変数を使用することを決定した場合、衝突の危険がありますが、それがあなた自身のコードだけであるなら、あなたはそれを避けることができるはずです。

def d(f):if getattr(f、 '_decorated_with_d'、False):raise SomeException( 'すでに装飾')@wraps(f)defラッパー(* args、** kwargs):print 'Calling func' return f(return) * args、** kwargs)wrapper._decorated_with_d = Trueラッパーを返す

他のオプションはこれである場合もあります:

def d(f):decoration_with = getattr(f、 '_decorated_with'、set())で、decoined_withの場合:raise SomeException( 'すでに装飾')@wraps(f)def wrapper(* args、** kwargs):print 'Calling func'は、f(* args、** kwargs)deco_with.add(d)wrapper._decorated_with = decoed_withリターンラッパーを返します。

これはあなたが使用されるすべてのデコレータをコントロールすると仮定します。 `_decorated_with`属性をコピーしないデコレータがあると、それが何で装飾されているのかわかりません。


2


私の解決策も提案します。

まず、別のデコレータを作ります。

class DecorateOnce(object):デフ__init __(self、f):self .__ f = f self .__ called = {}#装飾されたすべての関数を保存def __call __(self、toDecorate):#個別の関数名を取得funcName = toDecorate自分自身のfuncNameが呼び出された場合の.__ module__ toDecorate.func_name:raise Exception( 'このデコレータによって既に装飾されている関数')self .__ called [funcName] = 1 print funcName return self .__ f(toDecorate)

これで、あなたがこのデコレータで装飾したすべてのデコレータは、関数を一度だけ装飾するように自分自身を制限します。

@DecorateOnce def decorate(f):デフラッパー...


0


いや、使用する func_code`のプロパティは co_name`です。 下記を参照してください。変更されるのは、d()のdefの先頭にある2行だけです。

def d(f):f.func_code.co_name == 'wrapper'の場合:fを無視する#無視する(または代わりに例外をスローすることができる...)@wraps(f)def wrapper(* args、** kwargs):print 'calling func' return f(* args、** kwargs)リターンラッパー

また、関数オブジェクトに添付された明示的に定義されたプロパティを使うLukášLalinskýのアプローチも見てください。 「ラッパー」名が他の場所で使用される可能性があるので、これは好ましいかもしれません…​


-1


`f.func_code`を見ると、fが関数かラッパーかを知ることができます。