理解python中的装饰器

作者:平山

http://blog.51cto.com/2681882/2117746

一 什么是装饰器?

正如其名,装饰器的作用是为已经存在的对象增加额外功能(装饰),由此可使已有函数在无需代码改动的情况下增加额外功能;装饰器的本质是嵌套的函数且返回函数对象,即闭包。有关闭包的概念,可参考

《理解Python中的闭包》

一文。

二 装饰器应用场景举例

在介绍装饰器之前,我们思考下遇到如下场景时的解决思路,然后在此基础上,描述装饰器的意义和旨在解决哪些问题。

假如我们的func函数已经在使用,而且工作的挺好,func函数如下:

然而,某天针对该函数有新需求提出,暂时命名为需求1:为func函数增加性能度量,即测量函数的执行耗时。

针对需求1,一种可以简单理解的实现形式如下:

从实现来看,满足了需求1,但如果其余的函数也提出了类似的需求,如func1、func2都需要增加耗时测量,按上面的实现方式,func1、func2也需要在原功能前后增加time.time()代码,这样就造成了代码重复和冗余。

针对代码重复的问题,另一种实现方式是,定义一个专用的耗时测量函数,当需要测量某个函数时,直接将被测函数作为该测量函数的入参,实现形式如下:

从上面实现来看,功能耗时统计的代码被抽离并定义在共用函数count_time里,当需要测量某个函数时,直接调用该count_time函数即可。

但这种实现也是有问题的,需求是希望直接调用func()函数即可完成对功能耗时的测量,但目前的实现方式,需要使用另外一个函数count_time,显然改变了函数的调用方式。

三 装饰器为原有函数增加额外功能

针对上面场景描述及问题分析,我们使用装饰器解决该问题,首先定义装饰器函数如下:

从装饰器的定义来看,其实就是一个闭包实现,满足了在上篇对闭包三个条件的定义:

1) timer函数内部定义了wrapper函数,满足函数嵌套;

2) 内部函数wrapper使用了外部函数 timer的变量func_name;

3) 返回是一个内部函数的引用;

因此,装饰器本质是函数,是闭包的应用。

现在,我们用装饰器timer实现对func函数所提出的需求,即增加函数耗时测量功能。

使用装饰器的方法如下:

使用上面2步,调用func()时,虽然函数名相同,原func()函数也未做改动,但输出结果已经增加了耗时统计功能。如果不理解,请继续看上篇《理解Python中的闭包》中关于闭包的讲解。

另外,python的装饰器有个更简洁的表示方式,即使用“语法糖”@,如下:

使用装饰器语法糖@的调用方式

四 装饰器的作用

从上文分析,可以了解到,装饰器主要用于为已存在的函数对象附件额外的功能,而原先的函数的内部实现可以不做改动,调用方式也保持不变,而这些附加的功能是可以抽离出来作为共用的,避免了相似场景下代码的冗余。

其他资源分享:

关于装饰器:请参看http://i.youku.com/weiworld521 第21节;

看完本文有收获?请转发分享给更多人

关注 【小蟒社区】,一起学Python

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180921G0N8RN00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券