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

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

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


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

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

class tracer:def __init__(self, func):self.calls = 0self.func = funcdef __call(self, *args, **kwargs):self.calls += 1print('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 = nameself.pay = pay@tracerdef giveRaise(self, percent):self.pay *= (1.0 + percent)@tracerdef 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.

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基础算法-归并排序
  • 20231228在Firefly的AIO-3399J开发板的Android11使用Firefly的DTS配置单前后摄像头ov13850
  • Pandas的apply方法的应用练习
  • 2023-12-12LeetCode每日一题(下一个更大元素 IV)
  • SDG大数据平台简介
  • [ 云计算 | AWS ] 对比分析:Amazon SNS 与 SQS 消息服务的异同与选择
  • Java——功能开发思路
  • github鉴权失败
  • 数据结构——红黑树 and B-树
  • 【计算机网络】第四章摘要重点
  • 鸿蒙系列--组件介绍之容器组件
  • 卷积神经网络 反向传播
  • 感染了后缀为.[sqlback@memeware.net].2700勒索病毒如何应对?数据能够恢复吗?
  • 记录 Docker 中安装 ROS2
  • 深入理解依赖反转原则(DIP)
  • php的引用
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • classpath对获取配置文件的影响
  • Computed property XXX was assigned to but it has no setter
  • docker容器内的网络抓包
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • gulp 教程
  • leetcode-27. Remove Element
  • Mac转Windows的拯救指南
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • springboot_database项目介绍
  • 基于webpack 的 vue 多页架构
  • 模型微调
  • 前端js -- this指向总结。
  • 前嗅ForeSpider采集配置界面介绍
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​【已解决】npm install​卡主不动的情况
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • (1)虚拟机的安装与使用,linux系统安装
  • (70min)字节暑假实习二面(已挂)
  • (javaweb)Http协议
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (七)Activiti-modeler中文支持
  • (十六)视图变换 正交投影 透视投影
  • (十三)Maven插件解析运行机制
  • (四)鸿鹄云架构一服务注册中心
  • (转)3D模板阴影原理
  • .NET C# 使用GDAL读取FileGDB要素类
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • /bin/rm: 参数列表过长"的解决办法
  • @RequestMapping处理请求异常
  • @RequestParam,@RequestBody和@PathVariable 区别