If I have a function :
@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()
Is it possible to replace a decorator at runtime?
-
If the decorator is a function, just replace it.
aDecorator = otherDecorator
unbeknown : But this will not change myfunc1().Geo : I tried using your code, the function still executes with the initial decorator.miya : wow.. didn't expect this to happen. -
If you want to explicitely change the decorator, you might as well choose a more explicit approach instead of creating a decorated function:
deco1(myfunc1, arg1, arg2) deco2(myfunc1, arg2, arg3)
deco1() and deco2() would apply the functionality your decorators provide and call myfunc1() with the arguments.
Geo : Yes, I could have used a function that takes a function as it's first param, my function as it's second param, followed by the arguments, and have a pretty generic way of doing it.I was interested however, if I can replace a decorator with my own.I would like to "play" with other classes's behaviour -
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:
@aDecorator def 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(): pass myfunc2 = aDecorator(myfunc1) myfunc3 = bDecorator(myfunc1)
Edit: Or, to be a little clearer,
def _tempFunc(): pass myfunc1 = aDecorator(_tempFunc) myfunc1() myfunc1 = bDecorator(_tempFunc) myfunc1()
S.Lott : +1: aDecorate( func1 ) and bDecorate( func1 ) -
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_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')
Naturally, you can also incorporate the "decorator decorator" to preserve signatures, etc.
-
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 python class 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=True def my_decorator(f): if (some_condition): # modify the function return PrintCallInfo(f) else: # leave it as it is return f @my_decorator def foo(): print "foo" @my_decorator def bar(s): print "hello",s return s @my_decorator def foobar(x=1,y=2): print x,y return x + y foo() bar("world") foobar(y=5)
0 comments:
Post a Comment