首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python3 装饰器

1. 装饰器作用

装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的,说白了所谓装饰器,就是在不影响函数本身的情况下,为函数增加其他的附带功能,用于方便记录信息以及其他

2. 一个实例

某程序员接到要优化之前做的项目,首先他需要计算出各个模块的运行时间。现在有两种方案,一个是把程序执行时间功能写到模块内部,另一个则是另外写一个函数,但是修改模块内部是程序员大忌,所以采取第二种方案

运行结果:

补充:

程序最后一行是将 函数作为参数传递给 函数

因为函数也是一个对象(或者叫做是一个指针,就是内存地址,C 程序员应该能理解),对象可以被赋值给变量,所以,通过变量也能调用该函数,也直接传递给其他函数(将 main 函数地址传给 program_times)

函数对象有一个 属性,可以拿到函数的名字,其实就是将 main 的内存地址传给 f,f 就是 main() 函数,只不过是指向内存地址相同,名字不同罢了

3. 优化实例

上面的做法有一个问题,就是所有的 调用处都要改为 ,下面做一些改动来避免计时功能对 函数调用代码的影响

运行结果:

补充:

语句 是将 main 作为参数传递给 deco 函数,deco 函数会将 program_times 函数返回,然后在将 program_times 函数赋值给 main。此时的 main 函数其实已经是 program_times 函数了

4. 装饰器(不带参数)

上面的实例其实已经是装饰器了,但是在 python 中,我们可以使用 语法糖来精简装饰器代码

运行结果:

补充:

通过装饰器,我们可以在需要装饰器的函数上方加上 就可以,然后正常调用 mian 函数了

程序中 和 是完全等价的,本质是一样的

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会

5. 装饰器(带参数)

因为装饰器本质也是函数,是函数就有参数,接下来看一个有参数的装饰器

运行结果:

补充:

从例子中可以看到,对于被装饰函数需要支持参数的情况,我们只要使装饰器的内嵌函数支持同样的签名即可

例子中 main(1, 2) 其实是 deco(main(1, 2)) 的形式,先把 main 作为参数传给 deco 返回一个 program_times,之后再给 program_times 赋值

5. 装饰器(可变参数)

上面例子还有两个问题:

1. 如果多个函数拥有不同的参数形式,怎么共用同样的装饰器?

在 Python 中,函数可以支持 可变参数,所以装饰器可以通过可变参数形式来实现内嵌函数的签名

2. 如果装饰器本身需要支持参数,怎么实现?

如果装饰器本身需要支持参数,那么装饰器就需要多一层的内嵌函数

运行结果:

补充:

例子中 main(1, 2, 3) 其实是 deco("这个是 deco 的参数")(main(1, 2,3)) 的形式,首先执行 deco("这个是 deco 的参数") 返回的是 _deco 函数,再调用返回的 _deco 函数,参数是 main 函数,返回最终的 program_times 函数

6. 装饰器调用顺序

装饰器是可以叠加使用的,那么这是就涉及到装饰器调用顺序了。对于 Python 中的 语法糖,装饰器的调用顺序与使用 语法糖声明的顺序相反

运行结果:

补充:

例子中 main(1, 2) 其实是 deco1(deco2(main(1, 2))) 的形式,所以先执行 @deco_2

7. 内置装饰器在 Python 中有三个内置的装饰器,都是跟 class 相关的: 、 、

staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用

classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)

property 是属性的意思,表示可以通过通过类实例直接访问的信息

对于 staticmethod 和 classmethod 这里就不介绍了,通过一个例子看看 property

运行结果:

补充:

注意,对于 Python 新式类(new-style class),如果将上面的 装饰器所装饰的成员函数去掉,则 属性为只读属性,使用 进行赋值时会抛出异常。但是,对于 ,所声明的属性不是 的,所以即使去掉 装饰器也不会报错。

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

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券