装饰器
装饰器(decorator)可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
>>> def now():
... print('2015-3-25')
...
>>> f = now
>>> f()
2015-3-25
函数对象有一个__name__
属性,可以拿到函数的名字:
>>> now.__name__
'now'
>>> f.__name__
'now'
假设我们要增强 now()
函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称为“装饰器”(Decorator)。
import functools
def log(func):
# 把原始函数的__name__等属性复制到wrapper()函数中
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
执行结果如下:
>>> now()
call now():
2015-3-25
把 @log
放到 now()
函数的定义处,相当于执行了语句:
now = log(now)
由于 log()
是一个decorator,返回一个函数,所以,原来的now()
函数仍然存在,只是现在同名的 now
变量指向了新的函数,于是调用 now()
将执行新函数,即在 log()
函数中返回的 wrapper()
函数。
wrapper()
函数的参数定义是 (*args, **kw)
,因此,wrapper()
函数可以接受任意参数的调用。
带参数的装饰器
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
import functools
def log(text):
def decorator(func):
# 把原始函数的__name__等属性复制到wrapper()函数中
@functools.wraps(func)
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
这个3层嵌套的decorator用法如下:
@log('execute')
def now():
print('2015-3-25')
执行结果如下:
>>> now()
execute now():
2015-3-25
和两层嵌套的decorator相比,3层嵌套的效果是这样的:
>>> now = log('execute')(now)
我们来剖析上面的语句,首先执行log('execute')
,返回的是decorator
函数,再调用返回的函数,参数是now
函数,返回值最终是wrapper
函数。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。