Python中仅定义__eq__和__lt__不能直接支持>运算符,必须定义__gt__或通过functools.total_ordering装饰器补全比较方法。

为什么只定义 __eq__ 和 __lt__ 就能用 >、 等?
functools.total_ordering 不是魔法,它只是帮你自动生成其余比较方法的装饰器。前提是:你必须至少定义 __eq__(相等)和**一个**有序关系方法(推荐 __lt__),它才能推导出 __le__、__gt__、__ge__。如果你只定义 __eq__ 和 __gt__,它也能工作,但可读性和调试友好度下降。
常见错误现象:TypeError: ' —— 很可能漏了 __eq__,或没加 @total_ordering 装饰器,或装饰器写在了类定义之外。
- 必须把
@total_ordering直接写在class语句上方 - 必须实现
__eq__;否则所有比较都返回NotImplemented,最终抛TypeError - 推荐统一用
__lt__而非__gt__,因为sorted()、heapq等默认依赖
实际写法:以 Person 类按年龄排序为例
假设你要让 Person 实例能用 比年龄、== 比姓名和年龄都相同,并支持所有其他比较操作:
from functools import total_ordering
@total_ordering
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if not isinstance(other, Person):
return NotImplemented
return (self.name, self.age) == (other.name, other.age)
def __lt__(self, other):
if not isinstance(other, Person):
return NotImplemented
return self.age
<p>注意两个关键点:</p>
-
isinstance检查 +return NotImplemented是必须的,否则遇到不同类型(如person )会抛AttributeError,而不是安静地回退到反射比较 -
__eq__中用元组比较(name, age)是安全且简洁的写法,避免手动写and判断
哪些比较行为是自动补全的?
@total_ordering 只补这四个:__le__、__gt__、__ge__、__ne__。其中:
-
__le__(a, b)→ 等价于not b -
__gt__(a, b)→ 等价于b -
__ge__(a, b)→ 等价于not a -
__ne__(a, b)→ 等价于not a == b(只要实现了__eq__)
这意味着:如果你的 __lt__ 逻辑有歧义(比如对 None 返回 True),那么 __ge__ 的行为也会跟着错——它不独立判断,只是基于你写的 __lt__ 做逻辑翻转。
容易被忽略的兼容性陷阱
Python 2 和 Python 3 的比较机制差异在这里不体现,但以下两点常被跳过:
- 如果类继承自某个已有比较逻辑的父类,且父类没用
@total_ordering,子类加了装饰器后,__lt__可能被覆盖或未正确调用父类逻辑,建议显式调用super().__lt__(other) - 使用
dataclass时别混用:@dataclass(order=True)已内置全序支持,再套@total_ordering会冲突,抛TypeError: Cannot overwrite attribute __lt__ - 测试时别只测
和==,一定要验证>=是否符合直觉——尤其当__lt__里用了浮点数或近似比较时
真正麻烦的不是写法,而是当你把 __lt__ 写成基于哈希值或随机数时,@total_ordering 会忠实地把它扩散到所有比较中,而不会提醒你逻辑矛盾。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











