Today I'll present how to implement a decorator that enables a few ways to handle the embedded function. Such a mechanism is used in the celery project.
A quick celery task usage example:
@celery.task def add(x, y): return x + y res = add.delay(5,6) #asynchronous task res = add(5,6) #synchronous task
This is quite convenient, you may have such decorators applied to functions and still dynamically choose how the decorator should act in a specific context. An implementation of a similar decorator is presented below (with some test code):
class SomeDecorator(): def __call__(self, func, some_flag=False): def f(*args, **kwargs): if some_flag: print "Some flag is set" print "Some decorator routines" func(*args,**kwargs) setattr(f, "with_flag", lambda *args, **kwargs: \ self.__call__(func, some_flag=True)(*args,**kwargs)) return f @SomeDecorator() def test(a, b): print a, b if __name__ == '__main__': print "*****" test(5, b = "test") print "*****" test.with_flag(7, b="test2")
We have to be aware that after a decorator is used, each code referring to test will instead refer to f (function object type). To achieve our goal we have to provide f capabilities of performing different type of decorator activities. In this example code I have added a function attribute (line 11) which executes the default __call__ method, and still passes arguments/keyword arguments to the embedded function.
The standard output of running the presented code:
*****
Some decorator routines
5 test
*****
Some flag is set
Some decorator routines
7 test2
Feel free to use / modify / upgrade this code to achieve desired results.
Cheers!
KR
No comments:
Post a Comment