Python实例(七)

如何定义带参数的装饰器

场景:实现一个装饰器,用来检查被装饰函数的参数类型,装饰器可以通过参数指明函数参数的类型,调用时如果检测出类型不匹配则抛出异常

解决方法:
提取函数签名imspect.signature() 带参数的装饰器,也就是根据参数定制化一个装饰器,可以看成生产装饰器的工厂。每次调用typeassert,返回一个特定的装饰器,然后用它去装饰其他函数

from inspect import signature

def typeassert(*ty_args, **ty_kargs): ##装饰器工厂
    def decorator(func): ##装饰器
        # func -> a,b 
        # d = {'a': int, 'b': str}
        sig = signature(func) ##可以获取函数的签名,sig.parameters是参数的字典
        btypes = sig.bind_partial(*ty_args, **ty_kargs).arguments ##得到一个类型绑定的映射
        def wrapper(*args, **kargs):
            # arg in d, instance(arg, d[arg])
            for name, obj in sig.bind(*args, **kargs).arguments.items():
                if name in btypes:
                    if not isinstance(obj, btypes[name]):
                        raise TypeError('"%s" must be "%s"'%(name, btypes[name]))
            return func(*args, **kargs)
        return wrapper
    return decorator

@typeassert(int, str, list)
def f(a, b, c):
    print(a, b, c)

如何实现属性可修改的函数装饰器

场景:为分析程序内哪些函数执行时间开销较大,我们定义一个带timeout参数的函数装饰器,装饰功能如下:
1. 统计被装饰函数单次调用运行时间
2. 时间大于timeout的,将此次函数调用记录到log日记中
3. 运行时可修改timeout的值

from functools import wraps

import time
import logging

def warn(timeout):
    timeout = [timeout] ##python2解决timeout声明的方法
    def decorator(func):
        def wrapper(*args, **kargs):
            start = time.time()
            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):
            #nonlocal timeout ##关键字声明,只有Python3支持
            timeout[0] = k
        wrapper.setTimeout = setTimeout
        return wrapper
    return decorator

from random import randint
@warn(1.5)
def test():
    print('In test')
    while randint(0, 1): ##随机进入睡眠
        time.sleep(0.5)

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、付费专栏及课程。

余额充值