Python实现比较运算符_富比较方法实践

5次阅读

必须手动实现富比较方法,否则==仅判断是否为同一对象;当类表示有明确相等或大小关系的数据(如坐标点、分数)时,需定义__eq__、__lt__等以支持逻辑比较。

Python实现比较运算符_富比较方法实践

python中自定义类的比较行为,靠的是富比较方法(Rich Comparison Methods),比如 __eq____lt____le__ 等。它们不是自动继承或默认实现的,必须手动定义,否则两个实例用 == 比较时只是判断是否为同一对象(即 is),而不是按逻辑相等。

为什么要实现富比较方法

当你的类表示有明确“大小”或“相等”含义的数据(如坐标点、分数、日期、商品价格)时,直接用 ==、<code>!=运算符会更自然、可读性更强。否则就得写 a.equals(b)a.is_less_than(b) 这类冗长调用。

Python不会根据你实现了 __eq__ 就自动推导出 __ne__;也不会因写了 __lt____eq__ 就自动支持 __le__。每个方法都需显式定义,或借助 functools.total_ordering 装饰器减少重复代码。

六个核心富比较方法及其对应运算符

它们都接收 self 和另一个操作数 other,返回布尔值:

立即学习Python免费学习笔记(深入)”;

  • __eq__(self, other)==
  • __ne__(self, other)!=
  • __lt__(self, other)
  • __le__(self, other)
  • __gt__(self, other)>
  • __ge__(self, other)>=

注意:这些方法在不支持比较时应返回 NotImplemented(不是 NotImplementedError!),以便 Python 尝试调用 other 的对应反向方法(如 a 时 <code>a.__lt__(b) 返回 NotImplemented,则尝试 b.__gt__(a))。

实用实现技巧与常见陷阱

直接手写全部六个方法容易出错且重复。推荐两种稳妥方式:

  • 只实现 __eq__ + __lt__,再用 @total_ordering 装饰类,它会自动补全其余四个(__le____gt____ge____ne__
  • 在方法内部做类型检查:若 other 不是同类实例,返回 NotImplemented,不要抛异常或硬转类型
  • 避免在 __eq__ 中用 == 递归比较自身属性(比如属性本身也重载了 ==),要确保逻辑终止;必要时用 isinstance(other, type(self)) 判断后再解构比较
  • 对不可变对象(如 Point),可在 __eq__ 中直接比字段元组:return (self.x, self.y) == (other.x, other.y),简洁安全

一个完整可运行示例:二维点类

以下代码展示了带 @total_ordering 的典型写法:

from functools import total_ordering <p>@total_ordering class Point: def <strong>init</strong>(self, x, y): self.x = x self.y = y</p><pre class="brush:php;toolbar:false;">def __eq__(self, other):     if not isinstance(other, Point):         return NotImplemented     return self.x == other.x and self.y == other.y  def __lt__(self, other):     if not isinstance(other, Point):         return NotImplemented     # 先比 x,x 相同再比 y(字典序)     return (self.x, self.y) < (other.x, other.y)

使用示例

p1 = Point(1, 2) p2 = Point(1, 3) p3 = Point(1, 2)

print(p1 == p3) # True print(p1 != p2) # True print(p1 p1) # True

这个例子中,@total_ordering 让我们只写 __eq____lt__,就支持全部六种比较,且类型安全、语义清晰。

text=ZqhQzanResources