python中使用’@’ 作为函数的修饰符,可以在模块或者类的定义层内对函数进行修饰,出现在函数定义的前一行,不允许和函数定义在同一行。一个修饰符就是一个函数,它将被修饰的函数作为参数,并返回修饰后的同名函数或其他可调用的东西。
装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。
1、通过装饰器重用功能对多对象进行性能测试:
我们可以直接把计时逻辑方法my_func内部,但是这样的话,如果要给另一个函数计时,就需要重复计时的逻辑。所以比较好的做法是把计时逻辑放到另一个函数中(timecount),如下:
输出结果:
但是,上面的做法也有一个问题,就是所有的my_func调用处都要改为timecount(my_func)。下面,做一些改动,来避免计时功能对my_func函数调用代码的影响:
输出结果:
经过了上面的改动后,一个比较完整的装饰器(timecount)就实现了,装饰器没有影响原来的函数,以及函数调用的代码。例子中值得注意的地方是,Python中一切都是对象,函数也是,所以代码中改变了”my_func”对应的函数对象。
2、装饰器语法糖,在Python中,可以使用”@”语法糖来精简装饰器的代码
初始计时使用@语法糖表达:
输出结果:
加入wrapper后的表达:
输出结果:
使用了”@”语法糖后,我们就不需要额外代码来给”my_func”重新赋值了,雅思听力标准其实@timecount的本质就是my_func=timecount(my_func),当认清了这一点后,后面看带参数的装饰器就简单了。
3、被装饰的函数带参数
对于被装饰函数需要支持参数的情况,我们只要使装饰器的内嵌函数支持同样的表达式即可。
输出结果:
这里还有一个问题,如果多个函数拥有不同的参数形式,怎么共用同样的装饰器?在Python中,函数可以支持(*args, **kwargs)可变参数,所以装饰器可以通过可变参数形式来实现内嵌函数的签名。
输出结果:
4、带参数的装饰器
如果装饰器本身需要支持参数,那么装饰器就需要多一层的内嵌函数
输出结果:
5、装饰器调用顺序
装饰器是可以叠加使用的,那么这是就涉及到装饰器调用顺序了。对于Python中的”@”语法糖,英国留学费用装饰器的调用顺序与使用 @ 语法糖声明的顺序相反
输出结果:
Python内置装饰器
在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。
staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
输出结果:
classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
property 是属性的意思,表示可以通过通过类实例直接访问的信息