Python装饰器探幽


写在前面

python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

案例分析

如果要测试一个函数执行花费的时间,一般会采用如下方式:

def func():
    startTime = time.time()
    print("hello")
    time.sleep(1)
    print("world")
    endTime = time.time()
    print("{}ms".format((startTime - endTime) * 1000)

可是如果函数已经高度集成,或者需要测试的函数很多的情况下,逐个修改会很麻烦,此时可以使用装饰器拓展函数功能:

import time
def deco(func):
    startTime = time.time()
    func(*args,**kwargs)
    endTime = time.time()
    msecs = (endTime - startTime) * 1000
    print("{}ms".format(msecs))

def func():
    print("hello")
    time.sleep(1)
    print("world")

if __name__ == '__main__':
    f = func
    deco(f)

原理是函数也是python中的对象,可以作为参数传递给其他函数,也可以当作返回值。


将函数逐个传递给装饰器也不太现实,可以选择更方便的写法:

import time

def deco(func):
    #wrapper的参数也可以与func的参数保持一致,但会导致装饰器失去泛用性
    def wrapper(*args,**kwargs):
        startTime = time.time()
        #参数要与包裹函数(wrapper)的参数保持一致
        func(*args,**kwargs)
        endTime = time.time()
        msecs = (endTime - startTime) * 1000
        print("{}ms".format(msecs))
    return wrapper

#调用装饰器
@deco
def func(a,b):
    print("hello")
    time.sleep(1)
    print("world")

if __name__ == '__main__':
    #执行
    func(3,4)

多装饰器:

import time

def deco01(func):
    def wrapper(*args,**kwargs):
        print("this is deco01")
        startTime = time.time()
        func(*args,**kwargs)
        endTime = time.time()
        msecs = (endTime - startTime) * 1000
        print("{}ms".format(msecs))
        print("deco01 end")
    return wrapper

def deco02(func):
    def wrapper(*args,**kwargs):
        print("this is deco02")
        func(*args,**kwargs)
        print("deco02 end")
    return wrapper

@deco02
@deco01
def func(a,b):
    print("hello")
    time.sleep(1)
    print("world")

if __name__ == '__main__':
    func(3,4)

这里多装饰器的执行顺序类似于deco02(deco01(func)),deco02中func前的部分->deco01中func之前的部分->真正的func函数->deco01中func之后的部分->deco02中func之后的部分,绕两圈应该就明白了!一切皆是对象!