流畅的python笔记(十三)正确重载运算符

Python运算符重载,代码秒变高大上! 运算符重载是面向对象编程中的一项重要特性,它允许程序员为自定义的数据类型(如类)重新定义标准运算符的行为。这意味着,对于加号+、减号-等运算符,我们可以在不同类型的对象间赋予其特定的操作意义,而不局限于基本数据类型的操作。例如,在自定义的复数类中,我们可以重载+运算符,使其能够实现复数的加法操作。 阅读详情

目录

一、运算符重载基础

二、一元运算符

- + ~ abs()

x和+x何时不相等

与decimal.Decimal类有关的情况

与collections.Counter有关的情况

三、重载向量加法运算符+

四、重载标量乘法运算符*

五、比较运算符

六、增量赋值运算符


一、运算符重载基础

python对运算符重载加了一些限制。

  • 不能重载内置类型的运算符
  • 不能新键运算符,只能重载现有的
  • 某些运算符不能重载------is、and、or、not(位运算符&、|、~可以)

二、一元运算符

- + ~ abs()

一元运算符比如 - + ~等,每个一元运算符都对应一个特殊方法,abs()函数也是一元运算符,对应的特殊方法是__abs__。支持一元运算符只需要实现相应的特殊方法即可,这些特殊方法只有一个参数self。运算符基本规则:始终返回一个新对象,即不能修改self。即便是+,最好也是返回一个副本,不能返回引用。

 

  1.  为了计算-v,构建一个新的Vector实例,把self的每个分量都取反。
  2.  为了计算+v,构建一个新的Vector实例,传入self的各个分量。

x和+x何时不相等

与decimal.Decimal类有关的情况

  1. decimal.getcontext获取当前全局算术运算的上下文引用
  2. 把算术运算上下文的精度设为40
  3. 使用当前精度计算1/3
  4. 查看结果,小数点后有40个数字
  5. one_third == +one_third返回True
  6. 把精度降低为28,这是python3.4为Decimal算术运算设定的默认精度
  7. 现在,one_third == +one_third返回False
  8. 查看+one_third,小数点后有28个数字

one_third小数点后边始终有40个数字,第一个+one_third表达式返回的结果小数点后边也有40个数字,而第二个+one_third表达式返回结果的时候,当前算术运算上下文的精度已经变了,因此返回结果后边只有28个表达式,因此与one_third不同了。

与collections.Counter有关的情况

Counter实现了中缀运算符+,作用是把两个Counter的实例加一起,但是相加之后的结果会剔除掉零值和负值。对于Counter,一元运算符+等同于加上一个空Counter,因此会产生一个新的Counter且仅保留大于零的计数器。

三、重载向量加法运算符+

这一小节中的+是中缀运算符。

对于序列类型,+一般用于拼接,而*用于重复复制。但对于向量的说应该用向量加法才对。

如果两个Vector实例长度不同,则用零填充较短的向量。

满足以上要求的实现如下:

  1. pairs是一个生成器,可以生成(a, b)形式的元组,其中a来自self,b来自other。如果self和other的长度不同,使用fillvalue填充较短的那个可迭代对象。
  2. 构建一个新的Vector实例,使用生成器表达式计算pairs中各个元素的和。4
  3. 这种实现方式可以把Vector加到任何生成数字的可迭代对象上,但是如果对调操作数,用可迭代对象来加Vector,则会失败,因为python中缀运算符对应的特殊方法提供了特殊的分派机制。

对于表达式a+b,python解释器会执行以下几步操作:

__radd__是__add__的反向版本,可称为反向特殊方法,因为它是在右操作数上调用的,同理__rsub__也是反向特殊方法(也可叫右向特殊方法,r是right的意思)。因此为了让上边+的实现能支持右操作数是Vector,左操作数是生成数字的可迭代对象,只需要再实现__radd__即可。

        最简可用的__radd__实现如下:

上边重载的+支持可迭代对象与Vector之间的运算,但是如果提供的对象不可迭代,则__add__无法处理。

即使操作数是可迭代对象,但是它的元素不是数字,则还是不能与Vector中的浮点数元素相加。

如果由于类型不兼容导致运算符特殊方法失效,不应该返回TypeError,应该返回NotImplemented,返回NotImplemented时,另一个操作数所属类型还有机会执行运算,即python会尝试调用反向方法。

        下面是最终实现方案:

四、重载标量乘法运算符*

标量乘法,即元素级乘法,用标量乘向量中的每个分量,如下例子所示:

*运算符用于计算标量积,其对应的特殊方法是__mul__和__rmul__。

以上实现中,因为Vector内部是浮点数数组,任何数字乘以浮点数结果都是浮点数,因此scalar可以是int、bool、甚至fractions.Fraction实例等标量,但是不能是复数。为了判断scalar我们可以采用白鹅类型:使用isinstance()检查scalar的类型,不硬编码具体的类型,而是检查numbers.Real抽象基类,而且还支持以后声明为numbers.Real抽象基类的真实子类或虚拟子类的数值类型。

  1. 为了使用Real抽象基类,导入numbers模块。
  2. 如果scalar是numbers.Real的某个子类的实例,则进行标量乘积并返回一个新的Vector实例。
  3. 如果scalar不是numbers.Real的实例,返回NotImplemented,这样python会尝试在scalar上调用__rmul__方法。
  4. __rmul__方法定义,有了__rmul__,Vector就可以作为右操作数进行标量数乘。

这样,Vector类型实例就可以乘以很多的数字类型了,如下例子:

以下是python中中缀运算符列表:

 

五、比较运算符

pythone解释器对比较运算符(== != > < >= <=)的处理与前边提到的+,*等在两个方面有重大区别:

  1. 正向调用和反向调用使用同一方法,比如==,正向调用和反向调用都是__eq__方法,只不过把参数对调了,对于>=,正向调用的__gt__方法内部是委托给反向的__lt__方法来实现的,也是参数对调。
  2. 对于==和!=来说,如果反向调用失败,python会比较对象的ID,而不抛出TypeError。

接下来对前边几章中Vector.__eq__方法进行改进,原实现如下:

这会导致一个结果,任何可迭代对象,只要其分量与Vector实例相等,则==就判定他们相等。

为了解决这个问题,我们需要对操作数进行类型检查。

 

  1.  如果第二个操作数是Vector的实例或Vector的子类的实例,则正常进行比较。
  2.  否则,返回NotImplemented。

再看测试例子:

  1. 两个Vector实例,符合预期
  2. 判断正确,但是原因需要后文分析
  3. 有一个操作数是元组实例,因此判断False

在第二个测试例子中,Vector实例与Vector2d比较时,具体步骤如下:

  1. 为了计算vc == v2d,python调用Vector.__eq__(vc, v2d)
  2. 经Vector.__eq__(vc, v2d)确认,v2d不是Vector实例,因此返回NorImplemented
  3. python得到NotImplemented,尝试调用Vector2d.__eq__(v2d,vc)
  4. Vector2d.__eq__(v2d, vc)把两个操作数都变成元组,然后比较,结果是True

在第三个测试例子中,Vector实例和元组比较时,步骤如下:

  1. 为了计算va == t3,python调用Vector.__eq__(va, t3)
  2. 经Vector.__eq__(va,t3)确定,t3不是Vector实例,因此返回NotImplemented。
  3. python得到NotImplemented结果,尝试调用tuple.__eq__(t3, va)
  4. tuple.__eq__(t3, va)不知道Vector是什么,因此返回NotImplemented
  5. 对 == 来说,如果反向调用返回NotImplemented,python会比较对象的ID,作最后一搏。

对于!=运算符,其对应的__ne__方法会对__eq__返回的结果取反。

六、增量赋值运算符

增量赋值运算符不会改变不可变目标,而是新键实例,然后重新绑定变量。

  1. 赋值一份,v1_alias是v1对应对象的引用,id(v1_alias)等于id(v1)
  2. 这里是最开始绑定给变量v1的Vector实例的ID
  3. 增量加法运算
  4. v1的结果可以看到元素加法成功
  5. 但是通过查看id发现绑定给v1的是新的Vector实例
  6. 审查v1_alias,确认原来的Vector实例没被修改
  7. 增来乘法运算
  8. 同样,创建了新的Vector实例

如果一个类没有实现就地运算符对应的特殊方法比如__iadd__,那么增量赋值运算符只是语法糖,a += b与a = a + b完全等价。对不可变类型来说,只要定义__add__,+=直接就能用。但是如果实现了就地运算符方法,比如__iadd__,则计算a += b的时候会调用就地运算符方法,不会创建新实例而是修改左操作数。不可变类型,如Vector类,一定不能实现就地特殊方法!

        注意,与+相比,+=运算符对第二个操作数更宽容,很多时候 + 运算符的两个操作数必须是相同类型(但也有些时候第二个可以不是),而+=是就地修改左操作数,结果类型是确定的,所有相当于是用右操作数扩展左操作数,比如对于序列类型,一般可迭代对象就可以做右操作数。

 

 

 

 

 

 

 

 

【Python基础知识库】Python中重载 参考python 中的重载 在Python中,具有重载的思想却没有重载的概念。实际上,Python编程中具有重载的目的却无重载的行为,或者说python并不需要重载。python是一门动态语言,不需要声明变量类型,函数中可以接受任何类型的参数也就无法根据参数类型来支持重载,python没有必要去考虑参数的类型问题,这些都可以在函数内部判断处理,并无必要去在写一个函数。python 有多种传参方式,默认参数、可变参数、可变关键字参数,可以处理函数参数中参数可变的问题。 # python3.4 中提供的一个 阅读详情

相关推荐

Petalinux 2021.2 下 Qt组件编译报错?手把手教你修改bb文件搞定qt3d/qtquickcontrols2

本文详细解析了Petalinux 2021.2环境下Qt组件(如qt3d、qtquickcontrols2)编译报错的解决方案。通过修改bb文件或使用bbappend文件覆盖,有效解决`petalinux-build --sdk`命令执行时的源码获取失败或哈希校验不匹配问题,并提供验证与调试技巧,帮助开发者快速修复构建流程中断问题。

weixin_29188997的博客 214

Python编程:正确重载运算符

Python经典进阶教程!

weixin_56051592的博客 3035

统信UOS服务器上,达梦DM8数据库安装避坑全记录(附大小写敏感设置)

本文详细介绍了在统信UOS服务器版上部署达梦DM8数据库的全过程,包括环境准备、安装流程、数据库实例初始化及关键参数配置,特别是大小写敏感设置的注意事项。提供了从系统配置到性能优化的完整指南,帮助用户避免常见问题,确保数据库稳定运行。

weixin_30647423的博客 331

Python——运算符重载

Python——运算符重载1.加法运算符重载和减法运算符重载2.`__str__()`方法重载和`__ge__()`方法重载3.索引的切片重载 运算符重载指的是将运算符与类方法关联起来,每个运算符对应一个指定的内置方法。 Python通过重写一些内置方法,实现了运算符的重载功能。 1.加法运算符重载和减法运算符重载 加法运算符重载——__add__()方法 减法运算符重载——__sub__()方法 例 7-16 加法运算符重载和减法运算符重载的实现: #ex0716.py 加法运算符重载和减法运算符重

XQC_KKK的博客 9400

用Cursor+Node.js零代码搭建健康数据仪表盘:从数据录入到可视化全流程

本文详细介绍了如何利用Cursor AI编程助手和Node.js,无需手动编写代码,即可构建个人健康数据仪表盘的全流程。通过自然语言指令,实现从数据录入、存储到动态图表可视化的完整系统,展示了AI驱动开发在降低技术门槛、提升开发效率方面的强大能力。

gitlab7runner的博客 698

LangChain面试内容整理-知识点27:LangChain性能调优

LLM应用可能面临响应慢、成本高等性能问题。LangChain提供了一些优化方法和经验来提升性能和效率。

不务正业的猿 327

Python运算符重载

详解python运算符重载

weixin_39253570的博客 2051

Vue3 - 实现用户上传本地视频文件到服务器+上传进度条+暂停续传+中断取消上传等,视频上传后可在线播放预览已上传的视频,视频文件上传视频回显示例代码(支持Element、Antd等upload组件

实现视频上传和视频预览,vue3实现视频上传功能,上传视频回显,视频流上传播放功能,vue与axios上传视频并显示上传进度,upload组件实现视频文件上传视频回显,upload组件实现视频上传及进度条展示,视频上传及实时进度条显示,视频上传过程中如何中断上传,VUE3+element 上传视频,大文件分片上传+断点续传,axios大文件切片上传,Vue3上传视频后如何播放预览,上传本地视频到后端服务器及在线预览播放视频+移除视频+进度条上传,将已选视频上传服务端并可预览视频,详细实现选择视频并上传到服务

🏆 前端领域优质创作者 3112

Python中的运算符重载(Operator Overloading)

🔹。

鸟人的博客 1044

告别 DIFY 构建卡顿 / 失败!巧用 Makefile 一键构建本地 WEB 镜像,附核心避坑指南

本文详细介绍了DIFY本地源码构建WEB镜像的完整流程,重点解决因官方npm源不稳定导致的构建失败问题。通过修改web/Dockerfile文件启用国内npmmirror镜像源,可大幅提升依赖下载速度和稳定性。在DIFY根目录执行封装好的make build-web命令即可一键完成构建,无需手动编写复杂docker命令。文章还提供了前置环境准备、构建结果验证等实用指导,帮助开发者高效完成DIFY前端二次开发后的镜像构建验证。

2501_93651177的博客 181

【漏洞复现】WordPress Plugin NotificationX 存在sql注入CVE-2024-1698

技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。WordPress和WordPress plugin都是WordPress基金会的产品。WordPress Plugin NotificationX 存在安全漏洞,该漏洞源于对用户提供的参数转义不充分以及对现有 SQL 查询缺乏充分的准备,很容易通过“type”参数受到 SQL 注入攻击。

失心少年 1379

python正十三边形_流畅的python,Fluent Python 第十三章笔记 (正确重载运算符)

13.1运算符重载基础1、不能重载内置类型的运算符2、不能新建运算符,只能重载现有的3、某些运算符不能重载-----is、and、or、not(不过位运算符&、|和~可以)13.2 一元运算符- __neg__+ __poes__~ __invert__一元操作符要符合一个原则,返回一个新对象,不能修改self。from array import arrayimport mathimpo...

weixin_39769187的博客 227

Vue+OpenLayers:解决中国境内OpenStreetMap地图加载问题

然而,在使用OpenLayers和Vue框架搭建地图应用时,很多中国开发者可能会遇到一个常见问题:OpenStreetMap(OSM)地图无法正常加载。为了解决这个问题,我们可以使用其他方式获取地图数据,比如使用国内的地图服务提供商。通过使用国内地图服务商提供的地图数据,我们可以解决OpenStreetMap地图加载问题。然后,我们创建一个OpenLayers地图对象,并指定地图图层的源为国内地图服务商提供的地图URL。属性,可以将地图的中心点和缩放级别调整到我们需要的位置。

CodeWhizZ的博客 8269

流畅的Python(十三)-正确重载运算符

1. 一元运算符重载2.加法和乘法运算符重载3.比较运算符重载4.增量赋值运算符重载。

weixin_37901366的博客 1055

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

python 运算符重载_[流畅的Python]读书笔记之十三运算符重载

运算符重载Python 关于运算符重载的规则:不能重载内置类型的运算符不能新建,只能重载某些运算符不能重载--is、and、or 和 not一元运算符__neg____pos____invert__一元运算符是返回新建对象,不能修改self.加法+在 Vector 中__add__ 定义我觉得很厉害:def __add__(self, other): try: pairs ...

weixin_39883705的博客 107

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

python运算符重载 乘法_[流畅的Python]读书笔记之十三运算符重载

运算符重载Python 关于运算符重载的规则:不能重载内置类型的运算符不能新建,只能重载某些运算符不能重载--is、and、or 和 not一元运算符__neg____pos____invert__一元运算符是返回新建对象,不能修改self.加法+在 Vector 中__add__ 定义我觉得很厉害:def __add__(self, other):try:pairs = itertools.zi...

weixin_31767787的博客 414

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

python vector_[流畅的Python]读书笔记之十三运算符重载

运算符重载Python 关于运算符重载的规则:不能重载内置类型的运算符不能新建,只能重载某些运算符不能重载--is、and、or 和 not一元运算符__neg____pos____invert__一元运算符是返回新建对象,不能修改self.加法+在 Vector 中__add__ 定义我觉得很厉害:def 之所以要采取这种方式定义有以下好处:Vector 可以和任意长度的 iterable 类型...

weixin_39935388的博客 296

读书笔记:《流畅的Python》第13章 正确重载运算符

# 第13章 正确重载运算符 # 运算符重载的作用是让用户定义的对象使用中缀运算符或者一元运算符 """ 本章内容提要: 1 python如何处理中缀运算符中不同类型的操作数 2 使用鸭子类型或者显式类型检查处理不同类型的操作数 3 中缀运算符如何表明自己无法处理操作数的特殊行为 4 增量运算符(+=)的默认处理方式和重载方式 """ # 运算符重载基础 """ python对运算符重载施加的一些限制: 1.不能重载内置类型的运算符 2.不能新建运算符,.

Morbidmuse的博客 592

流畅的python第十三章正确重载运算符

运算符重载基础 不能重载内置类型的运算符 不能新建运算符,只能重载现有的 某些运算符不能重载-------is,and,or和not(不过位运算符&,|和~可以) 一元运算符 转载于:https://www.cnblogs.com/lgh344902118/p/8384831.html...

anyangyu0343的博客 116

《流畅的python》学习笔记及书评

《流畅的python》学习笔记 文章目录《流畅的python》学习笔记写在前面1. Python数据模型1.1 特殊方法2. 序列构成的数组2.1 内置序列类型2.2 列表推导和生成器表达式2.3 元组不仅仅是不可变的列表2.4 切片2.5 增量赋值2.6 排序2.7 数组、内存视图、NumPy和队列3. 字典和集合3.1 泛映射类型和字典推导3.2 常见的映射方法3.3 映射的弹性键查询3.4 字典的变种3.5 集合3.6 dict和set的背后4. 文本和字节序列4.1 字符和字节4.2 编码和解码4.

李英俊小朋友 2463

《流畅的Python》第十三章学习笔记

运算符重载的作用是让用户定义的对象使用中缀运算符或一元运算符中缀运算符是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术...

测试游记 117

流畅的 Python 个人笔记

从这个角度来看,生成器这种Python语言结构可以使用两种方式编写:含有yield关键字的函数,或者生成器表达式。生成器对象实现了这两个方法,因此从这方面来看,所有生成器都是迭代器。子类化内置对象是:自定义类继承Python内置类型(dict,list, str)利用Python的动态语言特定,在不修改源代码的基础上添加功能。函数确定,该函数会返回下述字符串中的一个。使用pirnt打印一个类对象,调用的是。在yield表达式处暂停。生成器与迭代器的语义对比。函数创建的对象是迭代器。

qq_42283061的博客 477

流畅的 Python 第二版(GPT 重译)(八)

第十五章:关于类型提示的更多内容 我学到了一个痛苦的教训,对于小程序来说,动态类型很棒。对于大型程序,你需要更加纪律严明的方法。如果语言给予你这种纪律,而不是告诉你“嗯,你可以做任何你想做的事情”,那会更有帮助。 Guido van Rossum,蒙提·派森的粉丝¹ 本章是第八章的续集,涵盖了更多关于 Python 渐进类型系统的内容。主要议题包括: 重载函数签名 typing.TypedDict用于对作为记录使用的dicts进行类型提示 类型转换 运行时访问类型提示 通用类型

龙哥盟 1576

流畅的Python学习

流畅的Python笔记 流畅的Python笔记 1 Python数据模型 2 数据结构 2.1 内置序列类型 2.2 列表推导与生成器表达式 2.3 元组 2.4 切片 2.5 序列对象上的+与* 2.6 sorted函数与list的sort方法 ...

zzulp的专栏 2125

《流畅的Python》读书笔记17: 第三部分 类和协议 - 运算符重载

运算符重载是让自定义类的实例能够响应 Python 的内置运算符(如//**等)的机制。这一特性使得我们编写的对象可以像内置数值类型一样自然地进行运算。Python 对运算符重载的限制比 C++ 或 Ruby 更严格:不能重载内置类型的运算符、不能创建新的运算符,且某些运算符(如isandornot)不能被重载。Python 通过特殊方法(如__add____sub____mul__等)来实现运算符重载。当 Python 解释器遇到a + b时,它会尝试调用。若a没有实现__add__(或返回。

4157

python 接口 、继承、重载运算符

文章目录1. 序列`__getitem__`2. `__setitem__`3. 抽象基类 learn from 《流畅的python》 1. 序列__getitem__ 如果没有 __iter__ 和 __contains__ 方法, Python 会调用 __getitem__ 方法, 设法让 迭代 和 in 运算符可用 class Foo: def __getitem__(self, pos): return range(0, 30, 10)[pos] f = Foo(

Michael是个半路程序员 543
上一篇: 流畅的python笔记(十二)继承的优缺点
下一篇: 流畅的python笔记(十四)可迭代的对象、迭代器和生成器
罗古洞的女婿
博客等级 码龄10年 1117粉丝 125原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值