python装饰器
python装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。装饰器实际上就是一个函数,其有如下两个特别之处:
1.参数是一个函数
2.返回值是一个函数
一、无参装饰器
这里先实现一个简单的装饰器功能,在任何函数执行前先打印hello world ,示例如下:
调用装饰器时,只需要在想要调用的函数前通过@+修饰器函数名称即可。另外在定义修饰器函数时,需要注意,最后return返回的是一个函数体,即wrapper,而不是wrapper(),如果后面加上括号,就代表函数的执行了。在注释部分我也写了下推导的函数执行流程。
不过上面的修饰器在执行时,发现在对后面有参数传入的情况下,执行会出现报错。接下来我们修改下让修饰器支持参数。
二、带参数修饰器
先看下面的代码和执行结果:
上面的代码我们修改了wrapper函数,使其支持函数传入,并将传入的函数又传参给了修饰器的参数func函数。执行的时候发现add函数可以正常执行,不过对于没有参数的函数run,在加了修饰器执行时出了报错,提示少了两个参数。
三、同时满足有参和无参
之所以使用修饰器,就是考虑到可以方便的处理通用情况问题,一会儿可以参考,一会儿又不可以传参,显然不具备通用性,这里可以借助python下的*args,**kwargs这对兄弟来解决该问题。*args表示任何多个无名参数,它是一个tuple,可以接受传入的任意个参数;**kwargs表示关键字参数,它是一个dict,可以接受任意多个key-vaule形式的参数,如a=b,c=100这类的,其会在接受后转换为{‘a’:’b’,’c’:100} 这样的格式。代码如下:
上面的代码执行并没有报错,不过细心查看,会发现print run.__name__ 这行执行的结果和我们想想的不同,本来打印函数的属性时,应该属出函数本身相关的属性信息,结果输出的是wrapper函数的。如果还是参照示例1中注释的函数推导的步骤推算,发现也确实应该输出为wrapper。哪如何避免该问题呢?
四、解决修饰器中函数属性改变
通过引入functools模块里的wraps方法,我们在修饰器定义的时候,再对func函数本身增加wraps修饰方法,就可以保留原方法的属性 。
五、总结
通过以上示例,我们得出有关修饰器的如下总结:
1、装饰的使用是通过@符号,放在函数的上面;
2、装饰器中定义的函数,要使用*args,**kwargs两对兄弟的组合;
3、需要functools.wraps在装饰器中的函数上把传进来的这个函数进一个包裹,这样就不会丢失原来的函数的__name__等属性。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/decorator/5573.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.