functools.wraps的特点:
- 被装饰函数不受装饰器的影响
- 装饰器的名字变成被装饰名字,外部调用到的被装饰函数的功能
- 有错误欢迎纠正
实现一个函数执行后计算时间的功能
写程序时,经常需要对函数的运行时间进行记时,如果每个函数的前后都写上time.clock(),需要修改的代码比较多,显得代码冗余,使用修饰器可以精简代码。
普通装饰器
def tictoc(func):
def wrapper():
'''something'''
begin = time.clock()
func()
end = time.clock()
print('time costs: %d' % (end - start))
#返回包装后的函数wrapper,后面会输出本函数的__name__对比区别
return wrapper
#通过传入函数本身的方式,再返回给函数本身,主程序中可以直接调用被装饰函数
func = tictoc(func)
#除了上述方法,还可以通过下面这种方法调用装饰器后的函数
@tictoc
def func():
def subFun():
print('this is subFun')
print('this is func')
func()
#@tictoc的作用和func = tictoc(func)一样
print(tictoc.__name__)
print(func.__name__)
到这里,输出一下wrapper.__name__
和func.__ name __
分别为:
tictoc
wrapper
这说明了func的名字变成了wrapper,这是程序设计中一个很严重的问题,丢失了被装饰函数的内容,即被装饰函数被装饰器修改了,会影响测试环节。
如何解决这个问题呢?
使用functools.wraps(func)装饰器
def tictoc(func):
@functools.wraps(func)
def wrapper():
'''something'''
begin = time.clock()
func()
end = time.clock()
print('time costs: %d' % (end - start))
#返回包装后的函数wrapper,后面会输出本函数的__name__对比区别
return wrapper
@tictoc
def func():
def subFun():
print('this is subFun')
print('this is func')
func()
#这次再打印看看
print(tictoc.__name__)
print(func.__name__)
输出如下:
tictoc
func
这次,func的名字是本身。
贴下面一段源码,深刻感受这个装饰器的作用,整体代码见github中下面这个文件:
tensorflow/models/research/slim/nets/nets_factory.py
if name not in networks_map:
raise ValueError('Name of network unknown %s' % name)
func = networks_map[name]
@functools.wraps(func)
def network_fn(images):
arg_scope = arg_scopes_map[name]. (weight_decay=weight_decay)
with slim.arg_scope(arg_scope):
return func(images, num_classes, is_training=is_training)
if hasattr(func, 'default_image_size'):
network_fn.default_image_size = func.default_image_size
return network_fn
如果没有这个装饰器,调用func时,无法调用到net模型的函数。