Fluent Python - Part13 正确重载运算符

运算符重载的作用是让用户定义的对象使用中缀运算符(如 + 和 |) 或一元运算符(如 - 和 ~)。说的宽泛一些,在 Python 中,函数调用(()),属性访问(.)和元素访问/切片([]) 也是运算符,不过本章只讨论一元运算符和中缀运算符。

在接下来的几节,我们将讨论:

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

运算符重载基础

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

一元运算符

下面是三个一元运算符和对应的特殊方法

  • -(__neg__)

    一元取负算术运算符。x = -2 -> -x = 2

  • +(__pos__)

    一元取正算术运算符。通常 x = +x, 但也有一些例外。

  • ~(__invert__)

    对整数按位取反,定义为 ~x = -(x+1)。如果 x 是 2,那么 ~x = -3

支持一元运算符很简单,只需实现相应的特殊方法。这些特殊方法只有一个参数,self.然后,使用符合所在类的逻辑实现。不过,要遵守运算符的一个基本规则:始终返回一个新对象。也就是说,不能修改 self, 要创建并返回合适类型的心实例。

重载向量加法运算符+

重载向量加法运算符很简单,即只要在类中实现 __add__ 方法即可,但Python为中缀运算符特殊方法提供了特殊的分派机制。对表达式 a+b 来说,解释器会执行以下几步操作。

  1. 如果 a__add__ 方法,而且返回值不是 NotImplemented, 调用 a.__add__(b), 然后返回结果。
  2. 如果 a 没有 __add__ 方法,或者调用 __add__ 方法返回 NotImplemented,检查 b 有没有 __radd__ 方法,如果有,而且没有返回 NotImplemented, 调用 b.__radd__(a) ,然后返回结果。
  3. 如果 b 没有 __radd__ 方法,或者调用 __radd__ 方法返回 NotImplemented, 抛出 TypeError, 并在错误消息中指明操作数类型不支持。
    在这里插入图片描述
  • tips: 别把 NotImplementedNotImplementedError 搞混了。前者是特殊的单例值,如果中缀运算符特殊方法不能处理给定的操作数,那么要把它返回给解释器。而 NotImplementedError 是一种异常,抽象类中的占位方法把它抛出,提醒子类必须覆盖。

众多比较运算符

Python 解释器对众多比较运算符(==, !=, >, <, >=, <=)的处理与前文类似,不过在两个方面有重大区别。

  • 正向和反向调用使用的是同一系列方法。例如,对 == 来说,正向和反向调用都是 __eq__ 方法,只能把参数对调了;而正向的 __gt__ 方法调用的是反向的 __lt__ 方法,并把参数对调。
  • ==!= 来说,如果反向调用失败,Python 会比较对象的 ID,而不抛出 TypeError。
  • Python3 的新行为:Python2 之后的比较运算符后备机制都变了。对于 __ne__ ,现在 Python3 返回结果是对 __eq__ 结果的取反。对于排序比较运算符,Python3 抛出 TypeError, 并把错误消息设为 unorderable types: int() < tuple()。在 Python2 中,这些比较的结果很怪异,会考虑对象的类型和ID,而且无规律可循。

增量赋值运算符

  • 增量赋值不会修改不可变目标,而是新建实例,然后重新绑定。
  • 如果一个类没有实现就地运算符,增量赋值运算符只是语法糖:a += b 的作用与 a = a + b 完全一样。对不可变类型来说,这是预期的行为,而且,如果定义了 __add__ 方法的话,不用编写额外的代码,+= 就能使用。
  • 如果实现了就地运算符方法,例如 __iadd__, 计算 a += b 的结果时会调用就地运算符方法。这种运算符的名称表明,它们会就地修改左操作符,而不会创建新对象作为结果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值