所谓装饰器(Decorator)就是一个返回函数的高阶函数,它可以在运行期间动态的增加函数的功能。
首先看一个简单的例子:
>>> def now():
print '2015-05-12'
>>>
>>> now()
2015-05-12
现在我想增加一些功能,但又不想改变原来函数。我们就可以使用装饰器。
>>> def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
>>> @log
def now():
print '2015-05-12'
>>> now()
call now():
2015-05-12
把@log放到now()函数的定义处相当于执行了语句:
now = log(now)
由于log是一个decorator,会返回一个函数,即log(now)返回了wrapper()函数。所以原来的now()函数会指向一个新的函数,即wrapper()。
而wrapper()函数又返回了原来的now()函数,并打印出指定的信息。
>>> now.__name__
'wrapper'
可以看出,now()函数现在指向的是wrapper()函数了。
若装饰器想带参数,就要加多一层嵌套了。
>>> def log(text):
def decorotar(func):
def wrapper(*args, **kw):
print '%s function %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorotar
>>>
>>> @log('execute')
... def now():
... print '2015-05-12'
...
>>> now()
execute function now():
2015-05-12
带了参数后的装饰器相当于执行log('execute')(now),即:首先执行的是log('execute'),返回decorator函数,
即一个没带参数的装饰器,然后再执行decorator(now)返回wrapper(),最后返回传入的now()函数。
这里函数的名称还是wrapper
>>> now.__name__
'wrapper'
但,这样跟我们原来设想的就会有出入了。因为,我们认为__name__这个属性返回的应该是我们原本调用的函数名称,即:now
而,Python内置的functools.wraps就可以帮助我们来解决以上的问题。所以,一个完整的装饰器是这样写的:
>>> import functools
>>> def log(func):
... @functools.wraps(func)
... def wrapper(*args, **kw):
... print 'call %s():' % func.__name__
... return func(*args, **kw)
... return wrapper
...
>>> @log
... def now():
... print '2015-05-12'
...
>>> now.__name__
'now'
带参数的装饰器:
>>> import functools
>>> def log(text):
... def decorator(func):
... @functools.wraps(func)
... def wrapper(*args, **kw):
... print '%s function %s():' % (text, func.__name__)
... return func(*args, **kw)
... return wrapper
... return decorator
...
>>> @log('execute')
... def now():
... print '2015-05-12'
...
>>> now.__name__
'now'
>>> now()
execute function now():
2015-05-12