装饰器
1.定义:
在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
2.分类:
不带参数:
def log(func): #接收函数做参数 def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper @log def now(): print('2015-3-25') #调用now,相当于执行log(now)
now=log(now)
now()
函数仍然存在,只是同名的now
变量指向了新的函数,于是调用now()
将执行新函数,即在log()
函数中返回的wrapper()
函数。
wrapper()
函数的参数定义是(*args, **kw)
,因此,wrapper()
函数可以接受任意参数的调用。在wrapper()
函数内,首先打印日志,再紧接着调用原始函数。
装饰器本身需要传入参数
def log(text): def decorator(func): def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator @log('execute') def now(): print('2015-3-25') --------------------- >>> now() #now = log('execute')(now) execute now(): 2015-3-25
1.首先执行log('execute')
,返回的是decorator
函数,
2.再调用返回的函数,参数是now
函数,返回值最终是wrapper
函数。
因为我们讲了函数也是对象,它有__name__
等属性,经过decorator装饰之后的函数,它们的__name__
已经从原来的'now'
变成了'wrapper'
:
>>> now.__name__
'wrapper'
因为返回的那个wrapper()
函数名字就是'wrapper'
,所以,需要把原始函数的__name__
等属性复制到wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错。加入后过于繁琐,可用@functools.wraps(func)代替
import functools def log(func): @functools.wraps(func) def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper --------------------------- 或者针对带参数的decorator: import functools def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator