函数装饰器(Function Decorators)
python中函数装饰器的使用和Java中注解类似, 直接在函数定义的前一行加上装饰器即可. python除了函数装饰器还有类的装饰器.
使用及原理
@decodef target(): pass
这样target
函数就被deco
装饰了, 其中deco
是一个接收一个函数为参数的函数.
decorators只是一种语法糖, 和以下代码是等价的
def target(): passtarget = deco(target)
两段代码的结果是一样的, target
指向的由deco
返回的函数, 而不一定指向原来定义的target
函数.
总结一下: 装饰器是一个接收一个函数作为参数(可能还有其他的参数)的函数, 它的返回值也是一个函数.
另外一个重要的是装饰器的函数在运行时马上被执行, 这个应该比较好理解. 也就是说当你运行时被装饰函数马上执行. 可以看看下面这个例子
def dec(func): print('the decorator function is excuting') return func@decdef target(): print('excute target()') def main(): passif __name__ == '__main__': main()
执行结果
the decorator function is excuting
也就是说不管有没有调用target
函数, target = dec(target)
都会在一开始马上执行.
另外装饰器还可以嵌套使用, 比如:
@deco1@deco2def target(): pass#等价于def target(): passtarget = deco1(deco2(target))
实现
首先是一个打印日志的装饰器, 输出函数名称, 传入的参数, 返回值
import functoolsdef log(func): @functools.wraps(func) def wrapper(*args, **kw): res = func(*args, **kw) print('excute %s(), ' % func.__name__, 'args:', args, kw,', res:', res) return res return wrapper@logdef add(a, b): return a + bdef main(): res = add(4, 5) print(res) print(add.__name__)if __name__ == '__main__': main() ''' excute add(), args: (4, 5) {} , res: 9 9 add '''
注意到我这里使用了@functools.wraps(func)
, 它可以让wrapper.__name__ = func.__name__
. 如果不加, 那么print(add.__name__)
的结果将是wrapper
.
另外一个例子, 记录函数运行时间
import functools, timedef clock(func): @functools.wraps(func) def clocks(*args, **kw): start = time.perf_counter() res = func(*args, **kw) elapsed = time.perf_counter() - start print('%s() excuted for %fs' % (func.__name__, elapsed)) return res return clocks@clockdef snooze(seconds): time.sleep(seconds)def main(): snooze(3) if __name__ == '__main__': main()''' snooze() excuted for 3.001641s '''
作者:前几
链接:https://www.jianshu.com/p/8d1410760809