第13章--正确重载运算符

第13章–正确重载运算符

本章将讨论:
• Python 如何处理中缀运算符中不同类型的操作数
• 使用鸭子类型或显式类型检查处理不同类型的操作数
• 中缀运算符如何表明自己无法处理操作数
• 众多比较运算符(如 ==、>、<=,等等)的特殊行为
• 增量赋值运算符(如 +=)的默认处理方式和重载方式

13.1python对重载运算符的限制

• 不能重载内置类型的运算符(list,dict,set…)
• 不能新建运算符,只能重载现有的
• 某些运算符不能重载——is、and、or 和 not(不过位运算符 &、| 和 ~ 可以)

13.2一元运算符

https://docs.
python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations

官方文档列出的一元运算符有三个
-(__neg__)
一元取负算术运算符。如果 x 是 -2,那么 -x == 2。
+(__pos__)
一元取正算术运算符。通常,x == +x,但也有一些例外。如果好奇,请阅读“x 和 +x
何时不相等”附注栏。
~(__invert__)
对整数按位取反,定义为 ~x == -(x+1)。如果 x 是 2,那么 ~x == -3。

一元运算符函数不能修改self,返回一个新实例

13.3-13.4重载加法运算符+乘法运算符*

a+b

a+b的所有注意事项适用于所有其他中缀运算符如- * \,下面只是具体以+为例子

对于a+b来说,python的调用顺序如下

(1) 如果 a 有 __add__ 方法,而且返回值不是 NotImplemented,调用 a.__add__(b),然后返回结果。
(2) 如果 a 没有 __add__ 方法,或者调用 __add__ 方法返回 NotImplemented,检查 b 有没有
__radd__ 方法,如果有,而且没有返回 NotImplemented,调用 b.__radd__(a),然后返回结果。
(3) 如果 b 没有 __radd__ 方法,或者调用 __radd__ 方法返回 NotImplemented,抛出 TypeError,
并在错误消息中指明操作数类型不支持。
在这里插入图片描述
在a的__add__方法中,因为传进来的参数b类型不确定,可能会造成方法报错TypeError,这样就不会有机会调用b.__radd__方法,而b的方法有可能会正确计算,所以一般的做法是在a.__add__中try catch捕捉TypeError,然后return NotImplemented。

NotImplemented 和 NotImplementedError

别把 NotImplemented 和 NotImplementedError 搞混了。前者是特殊的单例值,
如果中缀运算符特殊方法不能处理给定的操作数,那么要把它返回(return)
给解释器。而 NotImplementedError 是一种异常,抽象类中的占位方法把它抛
出(raise),提醒子类必须覆盖。

所有中缀运算符

在这里插入图片描述

13.5比较运算符

Python 解释器对众多比较运算符(==、!=、>、<、>=、<=)的处理与其他中缀运算符类似,不过在两个方面有重大区别。
• 正向和反向调用使用的是同一系列方法。例如,对 == 来说,
正向和反向调用都是 __eq__ 方法,只是把参数对调了;而正向的 __gt__ 方法调用的是
反向的 __lt__ 方法,并把参数对调。
• 对 == 和 != 来说,如果反向调用失败,Python 会比较对象的 ID,而不抛出 TypeError。
在这里插入图片描述

小结

本章首先说明了 Python 对运算符重载施加的一些限制:禁止重载内置类型的运算符,而且
限于重载现有的运算符,不过有几个例外(is、and、or、not)。
随后,本章讲解了如何重载一元运算符,接着重载
中缀运算符,首先是 +,它由 __add__ 方法提供支持。我们得知,一元运算符和中缀运算
符的结果应该是新对象,并且绝不能修改操作数。为了支持其他类型,我们返回特殊的
NotImplemented 值(不是异常),让解释器尝试对调操作数,然后调用运算符的反向特殊方
法(如 __radd__)。
如果操作数的类型不同,我们要检测出不能处理的操作数。本章使用两种方式处理这个问
题:一种是鸭子类型,直接尝试执行运算,如果有问题,捕获 TypeError 异常;另一种是
显式使用 isinstance 测试,__mul__ 方法就是这么做的。这两种方式各有优缺点:鸭子类
型更灵活,但是显式检查更能预知结果。如果选择使用 isinstance,要小心,不能测试具
体类,而要测试 numbers.Real 抽象基类,例如 isinstance(scalar, numbers.Real)。这在
灵活性和安全性之间做了很好的折中,因为当前或未来由用户定义的类型可以声明为抽象
基类的真实子类或虚拟子类
接下来的话题是众多比较运算符。我们通过 __eq__ 方法实现了 ==,而且发现 Python 在
object 基类中通过 __ne__ 方法为 != 提供了便利的实现。Python 处理这些运算符的方式与
>、<、>= 和 <= 稍有不同,具体而言是选择反向方法的逻辑不同,此外 Python 还会特别处
理 == 和 != 的后备机制:从不抛出错误,因为 Python 会比较对象的 ID,作最后一搏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值