案例:
为分析程序内哪些函数执行时间开销较大,我们定义一个带timeout参数的函数装饰器。装饰功能如下:
1.统计被装饰函数单次调用运行时间。
2.时间大于参数timeout的,将此次函数调用记录到log日志当中。
3.运行时间可修改timeout的值。
为包裹函数增添一个函数,用来修改闭包中使用的自由变量。在python3中,使用nonlocal访问嵌套作用域中的变量引用
from functools import wraps
from random import randint
import time
import logging #导入日志模块
def warn(timeout):
def decorator(func):
@wraps(func) #被装饰器装饰后的函数,函数名等函数属性的指向会发生改变,利用wraps把副作用给消除,指向保留原有函数的名称和属性
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs)
used = time.time() - start #计算运行用时
if used > timeout:
msg = '%s : %s > %s' %(func.__name__,used,timeout)
logging.warn(msg) #把运行超时的记录写进log日志中
return res
def setTimeout(k): #给用户自定义超时时间
nonlocal timeout #timeout为当前闭包内使用的私有变量,使用nonlocal访问嵌套作用域中的变量引用
timeout = k
wrapper.setTimeout = setTimeout #把函数作为warpper属性,用户可以通过调用设置timeout超时
return wrapper
return decorator
@warn(1.5) #语法糖装饰,传入时间参数
def test():
print('in test')
while randint(0,1):
time.sleep(0.5)
for _ in range(30):
test()
test.setTimeout(1) #自定义改变超时时间
for _ in range(30):
test()