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

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

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

要求:

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

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

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

解决方案:

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


  • 对于nonlocal关键字:

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

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


  • 方案示例:
import time, logging, randomdef 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]


上一篇:前端学习笔记47-高度塌陷和BFC


下一篇:jvm性能调优实战 - 47超大数据量处理系统是如何OOM的