1. 函数也是对象
在python中,函数也是对象,它有自己的方法,它可以传递下去。
函数传递
>>> def brown():
print 'brown'
>>> new_brown = brown # 函数对象传递
>>> new_brown()
brown
2. 什么是装饰器
装饰器实际上是函数,它以函数对象为参数,可以在它所装饰的函数的前或后添加一些其它的操作。你可以在执行(被装饰的)函数之前做一些预准备工作,也可以在执行(被装饰的)函数之后做一些清理工作,比如事后分析。
通常,当你wrap一个函数时,你应该在wrapper里调用它。你可以在wrapper里面随时调用它。
>>> from functools import wraps
>>> def deco(func): # 定义装饰器
@wraps(func)
def wrapper(*args, **kw_args):
print 'Do something prepared!'
func(*args, **kw_args)
print 'Do something cleanup!'
return wrapper
>>> @deco # 使用装饰器
def hello():
print 'Hello Brown!'
>>> hello()
Do something prepared!
Hello Brown!
Do something cleanup!
注意:
使用装饰器时使用了下述语法:
@deco def foo(): # To do something
其实等价于下述语法:
def foo(): # To do something foo = deco(foo)
定义装饰器时,在
wrapper()
函数上使用了functools.wraps
装饰器,目的是保留元信息(名字、文档字符串、注解和参数签名等)。你可以不使用它,函数照样能运行,但是当你执行hello.__name__
你会发现
hello
的函数名不再是hello
了,这意味着元信息丢了。
3. 装饰器的作用
装饰器可以用来:
- 引入日志
- 增加计时逻辑来检测性能
- 给函数加入事务的能力
4. 带参数的装饰器
注意,上面所讲的装饰器是没有参数的,e.g.@deco
;如果我们需要给装饰器传递参数,我们需要:定义一个返回(以被装饰函数作为参数的)装饰器的函数。有点拗口,简单地说,就是在我们之前的装饰器函数外再包裹一层函数,这个函数返回我们定义的无参数装饰器。
>>> from functools import wraps
>>> def deco_param(param):
def deco(func):
@wraps(func)
def wrapper(*args, **kw_args):
print 'Do something prepared!'
print 'Param is %s!' % param
func(*args, **kw_args)
print 'Do something cleanup!'
return wrapper
return deco
>>> @deco_param('BrownWong')
def hello():
print 'Hello Brown!'
>>> hello()
Do something prepared!
Param is BrownWong!
Hello Brown!
Do something cleanup!
注意:
@deco_param(param)
def hello():
# To do something
等价于
def hello():
# To do something
hello = deco_param(param)(hello)
5. 堆积装饰器
装饰器可以堆积起来,如下
@deco1
@deco2
def func():
# To do something
它等价于:
func = deco1(deco2(func))
6. 使用装饰器为函数打日志
我们看一个例子,例子会写一个用来打日志的装饰器,装饰器可以打印被装饰函数的位置、函数名、输入参数、函数消耗时间、函数返回值。
函数版本:
from functools import wraps
# 定义装饰器函数
def log_deco(logger):
def wrapper1(func):
@wraps(func)
def wrapper2(*args, **kw_args):
init_time = time.time()
result = func(*args, **kw_args)
spend_time = time.time() - init_time
logger.info('{}: {}(), params: {}, {}, result: {}, spend time: {}'.format(func.__module__, func.func_name, args, kw_args, result, spend_time))
return result
return wrapper2
return wrapper1
# 使用装饰器函数
@log_deco(logger)
def my_func(a, b, c=1):
time.sleep(1)
return a + b + c
if __name__ == '__main__':
my_func(1, 2, c=3)
类版本:
from functools import wraps
# 定义装饰器类
class LogDeco(object):
def __init__(self, logger):
self.logger = logger
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kw_args):
init_time = time.time()
result = func(*args, **kw_args)
spend_time = time.time() - init_time
self.logger.info('{}: {}(), params: {}, {}, result: {}, spend time: {}s'.format(\
func.__module__, func.func_name, args, kw_args, result, spend_time))
return result
return wrapper
# 使用装饰器
@LogDeco(logger)
def my_func(a, b, c=1):
time.sleep(1)
return a + b + c
if __name__ == '__main__':
my_func(1, 2, c=3)
Ref
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000
《Python核心编程》(第二版)