9-4 如何实现属性可修改的函数装饰器
一、实现
from functools import wraps import time import logging def warn(timeout): #带参数的装饰器,也就是内部能返回一个装饰器 def decorator(func): #定义一个真正的函数装饰器,接受一个函数参数 def wrapper(*args,**kargs): #在装饰器函数内部定义一个包裹函数 #统计运行时间 start = time.time() #记录func运行前的时间 res = func(*args,**kargs) used = time.time()-start if used >timeout: #如果输出超时导入日志当中 msg = '"%s":%s > %s' %(func.__name__,used,timeout) #定义消息格式,函数名,使用时间,超时时间 logging.warn(msg) #使用标准库函数记录日志 return res #包裹函数要返回被包裹函数 return wrapper #装饰器内部返回wrapper包裹函数 pass return decorator #返回一个装饰器
测试
from random import randint @warn(1.5) #装饰器,设置超时时间1.5s def test(): print('In test') while randint(0,1): #50%概率进入睡眠 time.sleep(0.5) #睡眠500ms for _ in xrange(30): #循环30次运行test test()
输出结果:
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
WARNING:root:"test":2.56699991226 > 1.5
In test
In test
In test
In test
WARNING:root:"test":2.06299996376 > 1.5
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
In test
WARNING:root:"test":1.50699996948 > 1.5
In test
WARNING:root:"test":1.50499987602 > 1.5
>>>
二、实现动态修改timeout功能
from functools import wraps import time import logging def warn(timeout): #带参数的装饰器,也就是内部能返回一个装饰器 def decorator(func): #定义一个真正的函数装饰器,接受一个函数参数 def wrapper(*args,**kargs): #在装饰器函数内部定义一个包裹函数 #统计运行时间 start = time.time() #记录func运行前的时间 res = func(*args,**kargs) used = time.time()-start if used >timeout: #如果输出超时导入日志当中 msg = '"%s":%s > %s' %(func.__name__,used,timeout) #定义消息格式,函数名,使用时间,超时时间 logging.warn(msg) #使用标准库函数记录日志 return res #包裹函数要返回被包裹函数 def setTimeout(k): #在装饰器内部定义一个新的函数, #timeout 是在wrapper闭包使用的自由变量,在这个函数不能直接对timeout进行修改 #这里py3修改timeout值会生成一个局部的变量 。可以使用 nonlocal timeout 来声明一个嵌套作用域下的变量 #py2可以读嵌套作用域的值,但不能修改修改会报错“找不到变量”,没有nonlocal 关键字就无法实现修改timeout变量对象的引用 #但py2可以把timeout实现一个可变对象 ,通过用可变对象修改的方式来实现。 nonlocal timeout timeout = k wrapper.setTimeout = setTimeout #setTimeout()函数做为wrapper()函数的属性, #未来客户就可以通过函数来调用setTimeout(),从而修改timeout的值。 return wrapper #装饰器内部返回wrapper包裹函数 pass return decorator #返回一个装饰器
测试
from random import randint @warn(1.5) #装饰器,设置超时时间1.5s def test(): print('In test') while randint(0,1): #50%概率进入睡眠 time.sleep(0.5) #睡眠500ms for _ in range(30): #循环30次运行test test() test.setTimeout(1) for _ in r ange(30): #循环30次运行test test()
输出结果:
py2可以读嵌套作用域的值,但不能修改修改会报错“找不到变量”,没有nonlocal 关键字就无法实现修改timeout变量对象的引用。但py2可以把timeout实现一个可变对象 ,通过用可变对象修改的方式来实现。
下面是python2实现方法
# -*- coding: cp936 -*- from functools import wraps import time import logging def warn(timeout): #带参数的装饰器,也就是内部能返回一个装饰器 timeout = [timeout] #py2不支持nonlocal关键字,把变量放入列表中 def decorator(func): #定义一个真正的函数装饰器,接受一个函数参数 def wrapper(*args,**kargs): #在装饰器函数内部定义一个包裹函数 #统计运行时间 start = time.time() #记录func运行前的时间 res = func(*args,**kargs) used = time.time()-start if used >timeout[0]: #如果输出超时导入日志当中 msg = '"%s":%s > %s' %(func.__name__,used,timeout[0]) #定义消息格式,函数名,使用时间,超时时间 logging.warn(msg) #使用标准库函数记录日志 return res #包裹函数要返回被包裹函数 def setTimeout(k): #在装饰器内部定义一个新的函数, #timeout 是在wrapper闭包使用的自由变量,在这个函数不能直接对timeout进行修改 #这里py3修改timeout值会生成一个局部的变量 。可以使用 nonlocal timeout 来声明一个嵌套作用域下的变量 #py2可以读嵌套作用域的值,但不能修改修改会报错“找不到变量”,没有nonlocal 关键字就无法实现修改timeout变量对象的引用 #但py2可以把timeout实现一个可变对象 ,通过用可变对象修改的方式来实现。 #nonlocal timeout #timeout = k timeout[0] = k wrapper.setTimeout = setTimeout #setTimeout()函数做为wrapper()函数的属性, #未来客户就可以通过函数来调用setTimeout(),从而修改timeout的值。 return wrapper #装饰器内部返回wrapper包裹函数 pass return decorator #返回一个装饰器
测试
from random import randint @warn(1.5) #装饰器,设置超时时间1.5s def test(): print('In test') while randint(0,1): #50%概率进入睡眠 time.sleep(0.5) #睡眠500ms for _ in range(30): #循环30次运行test test() test.setTimeout(1) for _ in range(30): #循环30次运行test test()
输出结果:
In test
WARNING:root:"test":2.0039999485 > 1.5
In test
In test
In test
In test
In test
In test
In test
WARNING:root:"test":2.00299978256 > 1.5
In test
In test
In test
In test
In test
In test
WARNING:root:"test":1.00300002098 > 1
In test
In test
In test
In test
In test
WARNING:root:"test":1.05200004578 > 1
In test
WARNING:root:"test":1.0039999485 > 1
In test
WARNING:root:"test":1.00400018692 > 1
In test
posted on 2018-05-10 09:44 石中玉smulngy 阅读(176) 评论(0) 编辑 收藏 举报