Python实现属性可修改的装饰器方式
作者:AllardZhao
这篇文章主要介绍了Python实现属性可修改的装饰器方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
如何实现属性可修改的函数装饰器
实际案例
为分析程序内哪些函数执行时间开销比较大,
我们定义一个带timeout参数的函数装饰器,timeout是一个时间阀值
比如运行时间超过1秒的都是比较慢的,这种函数比较可疑。
装饰器功能如下:
- 统计被装饰函数单词调用运行时间;
- 时间大于参数timeout的,将此次函数调用记录到log日志中;
- 运行时可修改timeout的值(可以动态修改timeout)。
解决方案
为包裹函数增加一个函数作为包裹函数的属性,用来修改闭包中使用的自由变量。
在python3中:使用nonlocal访问嵌套作用域中的变量引用。
代码演示
# _*_ encoding:utf-8 _*_ from functools import wraps from random import randint import time import logging # 内部统计一个算法的运行时间 def warn(timeout): """ 带参数装饰器也就是内部能返回一个装饰器 """ # python2中因为没有nonlocal,可以将timeout声明为可变对象 # timeout = [timeout] # 装饰器冬季func运行时间 def decorator(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.warning(msg) # if used > timeout[0]: # msg = '"%s": %s > %s' % (func.__name__, used, timeout[0]) # logging.warn(msg) # return res # 动态修改函数属性timeout值 def set_timeout(k): # python3声明嵌套作用域下变量,类似于global nonlocal timeout timeout = k # python2中使用可变对象修改timeout # timeout[0] = k # 将set_timeout函数作为wrapper属性,未来用户就可以通过函数来调用到它。 wrapper.set_timeout = set_timeout return wrapper return decorator # 测试代码 @warn(1.5) def test(): print('In test') # 随机进入睡眠状态,百分之50概率 while randint(0, 1): time.sleep(0.5) for _ in range(30): test() # 测试运行时修改timeout属性等于1 test.set_timeout(1) for _ in range(30): test() ''' 运行完前30个test函数后修改timeout=1。 运行时可以看到timeout从1.5变成了1,如下: WARNING:root:"test": 1.509084939956665 > 1.5 WARNING:root:"test": 1.004662036895752 > 1 '''
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。