要使自定义 class 的对象具有可比性,仅定义 `__eq__` 和 `__lt__` 家族中的几个成员就足够了吗?

To make objects of a custom class comparable, is it enough to define just a few of the members in `__eq__` and `__lt__` family?

假设我有一个 class,我想将其中的成员与常用运算符 ==<<=> 进行比较, 和 >=.

据我所知,这可以通过初始化定义魔术方法 __cmp__(a, b) 来实现,其中 returns -1 (a < b)、0 (a == b) 或 1 (a > b).

似乎__cmp__ was deprecated since Python 3 支持定义__eq____lt____le____gt___ge__ 方法分开。

我定义了 __eq____lt__,假设 __le__ 的默认值类似于 return a == b or a < b。下面的class似乎不​​是这样:

class PQItem:
    def __init__(self, priority, item):
        self.priority = priority
        self.item = item

    def __eq__(self, other):
        return isinstance(other, PQItem) and self.priority == other.priority

    def __lt__(self, other):
        return isinstance(other, PQItem) and self.priority < other.priority

class NotComparable:
    pass

x = NotComparable()
y = NotComparable()
# x < y gives error

我得到了这个结果:

>>> PQItem(1, x) == PQItem(1, y)
True
>>> PQItem(1, x) < PQItem(1, y)
False
>>> PQItem(1, x) <= PQItem(1, y)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: PQItem() <= PQItem()

这让我得出结论,我必须手动定义所有比较魔术方法才能使 class 具有可比性。有没有更好的方法?

为什么 __cmp__ 被弃用了?这似乎是一种更好的处理方式

对于两个对象ab__cmp__需要a < ba == b之一,并且 a > b 为真。但情况可能并非如此:考虑集合,其中 none of those 为真是很常见的,例如{1, 2, 3} 对比 {4, 5, 6}.

于是__lt__之类的东西被引入。但这让 Python 有两个独立的排序机制,这有点荒谬,所以在 Python 3.

中删除了不太灵活的机制。

您实际上不必实现所有六种比较方法。您可以使用 functools.total_ordering class 装饰器来帮助定义其余的魔术比较方法:

from functools import total_ordering
@total_ordering
class PQItem:
    def __init__(self, priority, item):
        self.priority = priority
        self.item = item

    def __eq__(self, other):
        return isinstance(other, PQItem) and self.priority == other.priority

    def __lt__(self, other):
        return isinstance(other, PQItem) and self.priority < other.priority