# -*- coding:utf-8 -*-
'''
为分析程序内哪些函数执行时间开销较大,定义一个timeout参数的函数装饰器.装饰功能:
1.统计被装饰函数单词调用运行时间.
2.时间大于参数timeout的,将此次函数调用记录到log日志中.
3.运行时可修改timeout的值.
解决方案:
为包裹函数增添一个函数,用来修改闭包中使用的自由变量.
在python3中:使用nonlocal访问嵌套作用域中的变量引用
'''
from functools import wraps
import time
import logging
from random import randint
def warn(timeout):
def decorator(func):
@wraps(func)
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)
return res
def setTimeout(k):
# timeout = k
# 这样是不允许的,因为timeout是在函数wrapper闭包内使用的自由变量
# 此句只会在setTimeout()创建一个属于本函数的本地变量
nonlocal timeout # 类似于global的关键字,使用在嵌套作用域下
timeout = k
wrapper.setTimeout = setTimeout # 将setTimeout()函数作为wrapper的属性
return wrapper
return decorator
# 因为python-2不支持nolocal关键字,所以做以下处理
def warn1(timeout):
timeout = [timeout] # attr -> [attr,]
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
used = time.time() - start
if used > timeout[0]:
msg = '"%s": %s > %s' % (func.__name__, used, timeout[0]) # timeout -> timeout[0]
logging.warn(msg)
return res
def setTimeout(k):
timeout[0] = k # timeout -> timeout[0]
wrapper.setTimeout = setTimeout # 将setTimeout()函数作为wrapper的属性
return wrapper
return decorator
@warn1(1.5)
def test():
print('IN test')
while randint(0, 1):
time.sleep(0.5)
if __name__ == '__main__':
for _ in range(30):
test()
test.setTimeout(1)
for _ in range(30):
test()
9-4修改属性的装饰器
最新推荐文章于 2024-09-14 15:36:45 发布