Python 装饰器初探

Posted 狂徒归来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 装饰器初探相关的知识,希望对你有一定的参考价值。

Python 装饰器初探

在谈及Python的时候,装饰器一直就是道绕不过去的坎。面试的时候,也经常会被问及装饰器的相关知识。总感觉自己的理解很浅显,不够深刻。是时候做出改变,对Python的装饰器做个全面的了解了。

1. 函数装饰器

直接上代码,看看装饰器到底干了些什么?

from functools import wraps
import time


def time_cost(func):
    @wraps(func)
    def f(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(end_time - start_time)
    return f


@time_cost
def test(*args, **kwargs):
    time.sleep(1.0)


if __name__ == "__main__":
    test()

上面的Python代码,运行后,会给出test函数的执行时间。代码的执行顺序大概如下,首先是将test作为值传递给time_cost函数,返回函数f,然后再调用f,这是带有time_cost装饰器的test函数的大致执行过程。

从中,不难看出,即使不使用装饰器符号,我们利用Python的语言特性,也能达成上述目的。用装饰器符号的好处是简化了代码,增加了代码的可读性。

这是一段非常简单的对函数使用装饰器的Python代码。等等,@wraps(func)是什么鬼?悄悄干了什么哇?

我们稍微修改下上式的代码,结果如下:

from functools import wraps
import time


def time_cost(func):
    def f(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(end_time - start_time)

    print('hello world')
    return f


@time_cost
def test(*args, **kwargs):
    time.sleep(1.0)


if __name__ == "__main__":
    print(test.__name__)

发现输出了hello world,同时输出test.__name__,居然变成了f,并不是我们预期的test。根据这样的输出结果,我们不难得出,其实被装饰器time_cost修饰过的函数test本质上已经等同于time_cost(test),此时访问test.__name__实际上访问的是time_cost(test).__name__,得到的当然就是f啦。当我们加上@wraps(func),此时test.__name__变成了test

以上是关于Python 装饰器初探的主要内容,如果未能解决你的问题,请参考以下文章

python使用上下文对代码片段进行计时,非装饰器

装饰器初探

装饰器初探

Python装饰器的前世今生!

装饰器设计模式初探(Java实现)

初探装饰器模式