当前位置: 首页 > news >正文

系统学习Python——装饰器:函数装饰器-[对方法进行装饰:基础知识]

分类目录:《系统学习Python》总目录


我们在前面的文章中编写了第一个基于类的tracer函数装饰器的时候,我们简单地假设它也应该适用于任何方法一一一被装饰的方法应该同样地工作,并且自带的self实例参数应该直接包含在*args的前面。但这一假设唯一的实际缺点就是它彻头彻尾地错了!当应用于类方法的时候,tracer的第一个版本失效了,因为self是装饰器类的实例,并且被装饰的主体类的实例没有包含在*args中。在python3.X和Python2.X中都是如此。

现在,我们可以在实际工作代码的上下文中看到这点。假设基于类的跟踪装饰器如下:

class tracer:
	def __init__(self, func):
		self.calls = 0
		self.func = func
	
	def __call(self, *args, **kwargs):
		self.calls += 1
		print('call %s to %s' % (self.calls, self.func.__name__))
		return self.func(*args, **kwargs)

@tracer
def spam(a, b, c):
	print(a + b + c)

我们可以得到如下输出:
输出结果
然而,类级别方法的装饰失效了:

class Person:
	def __init__(self, name, pay):
		self.name = name
		self.pay = pay

	@tracer
	def giveRaise(self, percent):
		self.pay *= (1.0 + percent)

	@tracer
	def lastName(self):
		return self.name.split()[-1]

我们可以得到如下输出:
输出结果
这里问题的根源在于tracer类的__call__方法的self参数是一个tracer实例,还是一个Person实例?其实我们两者都需要:tracer用于记录装饰器状态,Person用于指向最初的方法。实际上,self必须是tracer对象,以提供对tracer的状态信息(它的callsfunc)的访问;不管装饰一个简单函数还是装饰一个方法,都是如此。

遗憾的是,当我们用__call__把被装饰方法名称重绑定到一个类实例对象的时候,Python只向self传递了tracer实例;它根本没有在参数列表中传递Person主体。此外,由于tracer不知道我们要利用方法调用处理的Person`实例的任何信息,因此没有办法创建一个带有实例的绑定方法,也没有办法正确地分发调用。这不是一个漏洞,但却是一个非常值得注意的细节。

最后,前面的列表最终传递了太少的参数给被装饰的方法,并且导致了一个错误。在装饰器的__call__方法添加一行,以打印所有的参数来验证这一点一一正如我们所看到的,self是一个tracer实例,而Person实例则完全缺失:
输出结果
正如前面提到的,出现这种情况是因为仅当一个方法名绑定到一个简单函数时,Python才向self传递隐含的主体实例;当它是可调用类的实例时,就向self传递这个类的实例。从技术上讲,仅当方法是一个简单函数,而不是另一个类的可调用实例的时候,Python才会创建一个绑定的方法对象,其中包含了主体实例。

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.

相关文章:

  • 【JVM】一文掌握JVM垃圾回收机制
  • 计算机基础面试题 |04.精选计算机基础面试题
  • 微软开源,全平台通用:Shell 自动补全工具 | 开源日报 No.132
  • uni-app tabbar组件
  • R_handbook_统计分析
  • ES应用_ES原理
  • 【c语言】飞机大战2
  • centos 安装 配置 zsh
  • Stable Diffusion WebUI制作光影文字效果
  • Android Studio 如何隐藏默认标题栏
  • 为即将到来的量子攻击做好准备的 4 个步骤
  • QT QPluginloader 加载失败,出现Unknown error 0x000000c1的问题
  • 1.3 FMEA 实施指南
  • 车路协同中 CUDA 鱼眼相机矫正、检测、追踪
  • Qt高质量的开源项目合集
  • 浏览器强缓存和协商缓存
  • HarmonyOS应用程序包快速修复
  • 在ClickHouse中使用聚合组合器
  • appium安装运行报错的解决方案
  • MATLAB中./和/,.*和*,.^和^的区别
  • 上海青少年书法学习园开园:少年以巨笔书写《祖国万岁》
  • 中国田径巡回赛西安站完赛:男子跳远石雨豪夺冠
  • 终于,俄罗斯和乌克兰谈上了
  • “9+2”复式票,浦东购彩者拿下体彩大乐透1153万头奖
  • 李强:把做强国内大循环作为推动经济行稳致远的战略之举
  • 恒生银行回应裁员传闻:受影响的员工数目占银行核心业务员工总数约1%