Is it possible to replace a function/method decorator at runtime? [ python ] Is it possible to replace a function/method decorator at runtime? [ python ] python python

Is it possible to replace a function/method decorator at runtime? [ python ]


As Miya mentioned, you can replace the decorator with another function any point before the interpreter gets to that function declaration. However, once the decorator is applied to the function, I don't think there is a way to dynamically replace the decorator with a different one. So for example:

@aDecoratordef myfunc1():    pass# Oops! I didn't want that decorator after all!myfunc1 = bDecorator(myfunc1)

Won't work, because myfunc1 is no longer the function you originally defined; it has already been wrapped. The best approach here is to manually apply the decorators, oldskool-style, i.e:

def myfunc1():    passmyfunc2 = aDecorator(myfunc1)myfunc3 = bDecorator(myfunc1)

Edit: Or, to be a little clearer,

def _tempFunc():    passmyfunc1 = aDecorator(_tempFunc)myfunc1()myfunc1 = bDecorator(_tempFunc)myfunc1()


I don't know if there's a way to "replace" a decorator once it has been applied, but I guess that probably there's not, because the function has already been changed.

You might, anyway, apply a decorator at runtime based on some condition:

#!/usr/bin/env pythonclass PrintCallInfo:    def __init__(self,f):        self.f = f    def __call__(self,*args,**kwargs):        print "-->",self.f.__name__,args,kwargs        r = self.f(*args,**kwargs)        print "<--",self.f.__name__,"returned: ",r        return r# the condition to modify the function...some_condition=Truedef my_decorator(f):    if (some_condition): # modify the function        return PrintCallInfo(f)    else: # leave it as it is        return f@my_decoratordef foo():    print "foo"@my_decoratordef bar(s):    print "hello",s    return s@my_decoratordef foobar(x=1,y=2):    print x,y    return x + yfoo()bar("world")foobar(y=5)


Here's a terrific recipe to get you started. Basically, the idea is to pass a class instance into the decorator. You can then set attributes on the class instance (make it a Borg if you like) and use that to control the behavior of the decorator itself.

Here's an example:

class Foo:    def __init__(self, do_apply):        self.do_apply = do_applydef dec(foo):    def wrap(f):        def func(*args, **kwargs):            if foo.do_apply:                # Do something!                pass             return f(*args, **kwargs)        return func    return wrapfoo = Foo(False)@dec(foo)def bar(x):    return xbar('bar') foo.do_apply = True # Decorator now active!bar('baz')

Naturally, you can also incorporate the "decorator decorator" to preserve signatures, etc.