47. 实现属性可修改的函数装饰器

在某项目中,程序运行效率较差,为分析程序内哪些函数执行时间开销较大,我们实现了一个带timeout参数的函数装饰器。装饰功能如下:

@warn_timeout(1.5)
def func(a,b):
    ...

要求:

  1. 统计被装饰函数单次调用运行时间;

  2. 时间大于参数timeout的,将此次函数调用记录到log日志中;

  3. 运行时可修稿timeout的值。

解决方案:

为包裹函数增加一个函数,用来修改闭包中使用的自由变量。在Python3中,使用nonlocal关键词访问嵌套作用域中的变量引用。


  • 对于nonlocal关键字:

nonlocal表示将变量声明为外层变量(外层函数的局部变量,而且不能是全局变量)。

global表示将变量声明为全局变量。两个关键词都用于允许在一个局部作用域中使用外层的变量。


  • 方案示例:
import time, logging, random

def warn_timeout(timeout):
    def decorator(func):
        def wrap(*args, **kwargs):
            t0 = time.time()
            res = func(*args, **kwargs)
            used = time.time() - t0
            if used > timeout:
                logging.warning('%s: %s > %s' % (func.__name__, used, timeout))
            return res

        def set_timeout(new_timeout):
            nonlocal timeout
            timeout = new_timeout
        wrap.set_timeout = set_timeout
        return wrap
    return decorator

@warn_timeout(1)
def f(i):
    print('in f [%s]' % i)
    while random.randint(0, 1):
        time.sleep(0.6)

for i in range(10):
    f(i)

f.set_timeout(1.5)
for i in range(10):
    f(i)

结果:

in f [0]
in f [1]
in f [2]
in f [3]
in f [4]
WARNING:root:f: 2.40358567237854 > 1
in f [5]
in f [6]
WARNING:root:f: 1.2016241550445557 > 1
in f [7]
WARNING:root:f: 1.8050942420959473 > 1
in f [8]
in f [9]
WARNING:root:f: 1.8009305000305176 > 1
in f [0]
in f [1]
in f [2]
in f [3]
in f [4]
in f [5]
in f [6]
WARNING:root:f: 1.802403211593628 > 1.5
in f [7]
in f [8]
in f [9]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值