Home > Article > Backend Development > Python decorator usage study notes
In python, we often see the use of @func when defining functions. This is a decorator. A decorator is a function that takes a function as a parameter. It is often used to extend existing functions, that is, to add functions without changing the current function state.
def run(): print "I'm run."
I have such a function, and I want to know when this function starts and ends. I should write it like this
def run(): print time.ctime() print "I'm run." print time.ctime()
But if the function is not allowed to be modified, a decorator is needed
def count(func): def wrapper(): print time.ctime() ret = func() print time.ctime() return ret return wrapper @count def run(): print "I'm run." # print '2015-4-10'
eg:
def now(): print '2015-4-10' f = now f()
The function has a __name__ object that can be used as the function name defined by dir(func) func
now.__name__ # print 'now' f.__name__ # print 'now' print f # print '<function now at 0x000000000213A908>' print now # print '<function now at 0x000000000213A908>'
We print the log through the decorator
def log(func): def wrapper(*args, **kwargs): print "call %s()" % func.__name__ return func(*args, **kwargs) return wrapper @log def now(): print '2015-4-10' now() # print 'call now()'
In fact, the decorator modified function is equivalent to, now = log(now), that is, the decorator function takes the modified function as a parameter and assigns it to the variable with the same name
functools.wraps function
When we use the decorator, the __name__ value of now changes
# 没有使用前 now.__name__ # print 'now' # 使用后 now.__name__ # print 'wrapper'
When we use the decorator, now.__name__ uses the current now function, but after using it, the now function is actually log(now), that is, the return value of the log function is the wrapped wrapper. The solution is functools.wraps function.
Decoration closure, must call import functools
before use
def log(func): @functools.wraps(func) def wrapper(*args, **kwargs): ...
Decorator with parameters
If the decorator needs to pass in parameters, then you need to write a higher-order function that returns the decorator. Writing it is more complicated.
def login(level): def _deco(func): def wrapper(*args, **kwargs): if level >= 5: print '用户 VIP 等级 %d' % int(level-5) else: print '用户 屌丝 等级 %d' % abs(level-5) return func(*args, **kwargs) return wrapper return _deco @login(5) def user(username): print 'welcome, %s' % username # 用户vip 等级0 # welcome, mink user('mink')
The decorator with parameters is equal to func = decorator function (decorator parameter) (func)
Decorator class
Through the __call__ of the class, you can use the class like a function
class A(object): def __init__(self, func): self.func = func def __call__(self): return self.func() ** 2 @A def foo(): return 10 print foo() # print 100