9-4修改属性的装饰器

# -*- 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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值