这篇文章将为大家详细讲解有关使用Python怎么实现一个函数装饰器,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
Python可以做什么
Python是一种编程语言,内置了许多有效的工具,Python几乎无所不能,该语言通俗易懂,容易入门,功能强大,在许多领域中都有广泛的应用,例如最热门的大数据分析,人工智能,网页开发等。
<强>跟踪调用强>
如下代码定义并应用一个函数装饰器,来统计对装饰的函数的调用次数,并且针对每一次调用打印跟踪信息。
class 示踪剂: def 才能__init__(自我,函数): ,,,self.calls =0 ,,,self.func =函数 def 才能__call__(自我,* args): ,,,self.calls +=1 ,,,print (& # 39; call % s 用% & # 39;,% (self.calls, self.func.__name__)) ,,,self.func (* args) @tracer def 垃圾邮件(a, b, c): 打印才能(a +, b +, c)
这是一个通过类装饰的语法写成的装饰器、测试如下:
在祝辞祝辞,垃圾邮件(1、2、3) call 1,用垃圾邮件 6 祝辞祝辞祝辞,垃圾邮件(& # 39;一个# 39;& # 39;b # 39;, & # 39; c # 39;) call 2,用垃圾邮件 美国广播公司 在祝辞祝辞spam.calls 2 在祝辞祝辞,垃圾邮件 & lt; __main__.tracer  object at 0 x03098410>
运行的时候,示踪剂类和装饰的函数分开保存,并且拦截对装饰的函数的随后的调用,以便添加一个逻辑层来统计和打印每次调用。
装饰之后,垃圾邮件实际上是示踪剂类的一个实例。
@装饰器语法避免了直接地意外调用最初的函数。考虑如下所示的非装饰器的对等代码:
calls =0 * args def 示踪(函数): global 才能调用 calls 才能+=1 打印才能(& # 39;call % s 用% & # 39;%(电话,func.__name__)) ,,func (* args) def 垃圾邮件(a, b, c): 打印才能(a + b + c)
测试如下:
在祝辞祝辞,垃圾邮件(1、2、3) 6 在祝辞祝辞,示踪剂(垃圾邮件,1、2、3) call 1,用垃圾邮件 6
这一替代方法可以用在任何函数上,且不需要特殊的@语法,但是和装饰器版本不同,它在代码中调用函数的每个地方都需要额外的语法。尽管装饰器不是必需的,但是它们通常是最为方便的。
<强>扩展——支持关键字参数强>
下述代码时前面例子的扩展版本,添加了对关键字参数的支持:
class 示踪剂: def 才能__init__(自我,函数): ,,,self.calls =0 ,,,self.func =函数 def 才能__call__(自我,* args, * * kargs): ,,,self.calls +=1 ,,,print (& # 39; call % s 用% & # 39;,% (self.calls, self.func.__name__)) ,,,self.func (* args, * * kargs) @tracer def 垃圾邮件(a, b, c): 打印才能(a +, b +, c) @tracer def 蛋(x, y): 打印才能(x * * y)
测试如下:
在祝辞祝辞,垃圾邮件(1、2、3) call 1,用垃圾邮件 6 在祝辞祝辞,垃圾邮件(=4,b=5, c=6) call 2,用垃圾邮件 15 在祝辞祝辞,蛋(2,16) call 1,用鸡蛋 65536 在祝辞祝辞,鸡蛋(4,y=4) call 2,用鸡蛋 256年
也可以看的到,这里的代码同样使用【类实例属性】来保存状态,即调用的次数<代码>自我。电话> 代码。包装的函数和调用计数器都是针对每个实例的信息。
<强>使用def函数语法写装饰器强>
使用def定义装饰器函数也可以实现相同的效果。但是有一个问题,我们也需要封闭作用域中的一个计数器,它随着每次调用而更改。我们可以很自然地想到全局变量,如下:
calls =0 def 示踪(函数): def 才能包装器(* args, * * kargs): ,,,global 调用 ,,,calls +=1 ,,,print (& # 39; call % s 用% & # 39;%(电话,func.__name__)) ,,,return func (* args, * * kargs) return 才能包装 @tracer def 垃圾邮件(a, b, c): 打印才能(a + b + c) @tracer def 蛋(x, y): 打印才能(x * * y)
这电话里定义为全局变量,它是跨程序的,是属于整个模块的,而不是针对每个函数的,这样的话,对于任何跟踪的函数调用,计数器都会递增,如下测试: