完善装饰器细节

1. 传递参数

上一篇实现了一个监测函数执行时间的装饰器,但这个装饰器存在缺陷,它只能装饰那些没有参数的函数,下面的用法就是有问题的

import time


def cost(func):
    def warpper():
        t1 = time.time()
        res = func()
        t2 = time.time()
        print(func.__name__ + "执行耗时" +  str(t2-t1))
        return res
    return warpper


@cost
def test(sleep_time):
    time.sleep(sleep_time)


test(1)

程序报错,原因在于test函数有一个sleep_time参数,但是在执行res = func()时,却没有传递这个参数,对装饰器稍作修改,修改后代码如下

def cost(func):
    def warpper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        print(func.__name__ + "执行耗时" +  str(t2-t1))
        return res
    return warpper

在函数warpper中增加可变参数,在调用执行被装饰的函数时传递这些可变参数,这样就不会有问题了,现在,这个装饰器可以装饰任何你想装饰的函数

2. 修复函数

2.1 自省信息

函数被装饰以后,一些原本属于自己的自省信息会丢失,先来看装饰前的样子

def test(sleep_time):
    """
    测试装饰器
    :param sleep_time:
    :return:
    """
    time.sleep(sleep_time)


print(test.__name__)
print(test.__doc__)

执行输出结果

test

    测试装饰器
    :param sleep_time:
    :return:

2.2 自省信息丢失

程序会输出函数的名称和函数的注释doc信息,但是被装饰以后,这些信息就会丢失

@cost
def test(sleep_time):
    """
    测试装饰器
    :param sleep_time:
    :return:
    """
    time.sleep(sleep_time)


print(test.__name__)
print(test.__doc__)

程序输出结果为

warpper
None

2.3 修复丢失信息

可以看到,实际输出的都是warpper的自省信息,这是我们不希望看到的,为此,我们要使用一项修复技术

import time
from functools import wraps


def cost(func):
    @wraps(func)
    def warpper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        print(func.__name__ + "执行耗时" +  str(t2-t1))
        return res
    return warpper

@cost
def test(sleep_time):
    """
    测试装饰器
    :param sleep_time:
    :return:
    """
    time.sleep(sleep_time)


print(test.__name__)
print(test.__doc__)

functools模块有一个wraps函数,它可以避免函数被装饰后丢失自省信息,增加@wraps(func)即可,这样,程序最后输出的就test自身的信息

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案