为何Python的sort方法忽略类中定义的total_ordering排序逻辑?
问题原因分析
首先,不管用@functools.total_ordering装饰普通类还是dataclass,排序不符合预期的核心原因几乎都是自定义比较逻辑(尤其是__gt__)没有匹配你想要的排序规则。
1. @functools.total_ordering的推导逻辑
这个装饰器的作用是基于你实现的__eq__和单个比较方法(比如__gt__),自动推导其余比较方法。比如:
- 当你实现
__gt__,它会把__lt__推导为:lambda self, other: not (self > other or self == other) - 而列表的
sort()默认是升序排序,依赖的是__lt__方法的结果。
你的预期排序p值顺序为[0,2,4,5,6,1,3]不是常规的数值大小排序,而是一个自定义的优先级顺序。如果你的__gt__只是简单比较p的数值大小(比如return self.p > other.p),那推导出来的__lt__也会基于数值大小,自然得不到你要的结果。
2. Dataclass的潜在冲突
如果你把类改成dataclass时:
- 如果指定了
@dataclass(order=True),dataclass会自动生成所有比较方法,这些自动生成的方法会覆盖你手动实现的__gt__和total_ordering推导的方法,除非你明确手动覆盖这些方法。 - 如果没指定
order=True,dataclass不会生成比较方法,这时候和普通类用total_ordering的逻辑一致,问题还是出在你的__gt__逻辑不符合自定义排序规则。
解决方向
要实现预期的排序,你需要:
- 先定义一个表示优先级的映射,比如:
PRIORITY = {0: 0, 2: 1, 4: 2, 5: 3, 6: 4, 1: 5, 3: 6} - 然后在
__gt__中基于这个优先级来判断:def __gt__(self, other): if not isinstance(other, Entry): return NotImplemented return PRIORITY[self.p] > PRIORITY[other.p]
这样total_ordering推导的__lt__才会符合你的自定义排序规则,sort()才能得到预期结果。
如果用dataclass,要么不要加order=True,要么手动覆盖所有比较方法(或者只实现__lt__,因为sort()主要依赖它),确保逻辑基于自定义优先级。
内容的提问来源于stack exchange,提问作者Abhijit Sarkar
相关产品推荐
相关产品推荐

