函数装饰器(Function Decorators)
python中函数装饰器的使用和Java中注解类似, 直接在函数定义的前一行加上装饰器即可. python除了函数装饰器还有类的装饰器.
使用及原理
@deco
def target():
pass
这样target
函数就被deco
装饰了, 其中deco
是一个接收一个函数为参数的函数.
decorators只是一种语法糖, 和以下代码是等价的
def target():
pass
target = deco(target)
两段代码的结果是一样的, target
指向的由deco
返回的函数, 而不一定指向原来定义的target
函数.
总结一下: 装饰器是一个接收一个函数作为参数(可能还有其他的参数)的函数, 它的返回值也是一个函数.
另外一个重要的是装饰器的函数在运行时马上被执行, 这个应该比较好理解. 也就是说当你运行时被装饰函数马上执行. 可以看看下面这个例子
def dec(func):
print('the decorator function is excuting')
return func
@dec
def target():
print('excute target()')
def main():
pass
if __name__ == '__main__':
main()
执行结果
the decorator function is excuting
也就是说不管有没有调用target
函数, target = dec(target)
都会在一开始马上执行.
另外装饰器还可以嵌套使用, 比如:
@deco1
@deco2
def target():
pass
#等价于
def target():
pass
target = deco1(deco2(target))
实现
首先是一个打印日志的装饰器, 输出函数名称, 传入的参数, 返回值
import functools
def 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
@log
def add(a, b):
return a + b
def 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, time
def 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
@clock
def snooze(seconds):
time.sleep(seconds)
def main():
snooze(3)
if __name__ == '__main__':
main()
'''
snooze() excuted for 3.001641s
'''