20

関数がある場合:


@aDecorator
def myfunc1():
  # do something here

if __name__ = "__main__":
  # this will call the function and will use the decorator @aDecorator
  myfunc1() 
  # now I want the @aDecorator to be replaced with the decorator @otherDecorator
  # so that when this code executes, the function no longer goes through
  # @aDecorator, but instead through @otherDecorator. How can I do this?
  myfunc1()

実行時にデコレータを置き換えることは可能ですか?

4

7 に答える 7

17

ミヤが述べたように、インタープリターがその関数宣言に到達する前の任意の時点で、デコレーターを別の関数に置き換えることができます。ただし、デコレータが関数に適用されると、デコレータを別のものに動的に置き換える方法はないと思います。たとえば、次のようになります。

@aDecorator
def myfunc1():
    pass

# Oops! I didn't want that decorator after all!

myfunc1 = bDecorator(myfunc1)

myfunc1 は最初に定義した関数ではないため、機能しません。すでにラップされています。ここでの最善のアプローチは、oldskool スタイルのデコレータを手動で適用することです。

def myfunc1():
    pass

myfunc2 = aDecorator(myfunc1)
myfunc3 = bDecorator(myfunc1)

編集:または、もう少し明確にするために、

def _tempFunc():
    pass

myfunc1 = aDecorator(_tempFunc)
myfunc1()
myfunc1 = bDecorator(_tempFunc)
myfunc1()
于 2009-03-13T13:55:56.350 に答える
3

これがあなたが始めるための素晴らしいレシピです。基本的に、アイデアはクラスインスタンスをデコレータに渡すことです。次に、クラスインスタンスに属性を設定し(必要に応じてBorgにします)、それを使用してデコレータ自体の動作を制御できます。

次に例を示します。

class Foo:
    def __init__(self, do_apply):
        self.do_apply = do_apply

def dec(foo):
    def wrap(f):
        def func(*args, **kwargs):
            if foo.do_apply:
                # Do something!
                pass 
            return f(*args, **kwargs)
        return func
    return wrap

foo = Foo(False)
@dec(foo)
def bar(x):
    return x

bar('bar') 
foo.do_apply = True 
# Decorator now active!
bar('baz')

もちろん、「デコレータデコレータ」を組み込んで署名などを保存することもできます。

于 2009-03-13T13:59:40.710 に答える
2

デコレーターを明示的に変更したい場合は、装飾された関数を作成する代わりに、より明示的なアプローチを選択することもできます。

deco1(myfunc1, arg1, arg2)
deco2(myfunc1, arg2, arg3)

deco1() と deco2() は、デコレーターが提供する機能を適用し、引数を指定して myfunc1() を呼び出します。

于 2009-03-13T13:53:41.440 に答える
1

確かに-関数オブジェクトを取得して、それで好きなことをすることができます:

# Bypass a decorator

import types

class decorator_test(object):

    def __init__(self, f):
        self.f = f

    def __call__(self):
        print "In decorator ... entering: ", self.f.__name__
        self.f()
        print "In decorator ... exiting: ", self.f.__name__


@decorator_test
def func1():
    print "inside func1()"

print "\nCalling func1 with decorator..."
func1()

print "\nBypassing decorator..."
for value in func1.__dict__.values():
    if isinstance(value, types.FunctionType) and value.func_name == "func1":
        value.__call__()
于 2010-11-16T23:26:59.363 に答える
-3

デコレータが関数の場合は、それを置き換えるだけです。

aDecorator = otherDecorator
于 2009-03-13T13:43:58.673 に答える