问题
Let's say I have a class, members of which I want to compare with the usual operators ==, <, <=, >, and >=.
As I understand, this could be accomplished by initializing defining magic method __cmp__(a, b) which returns -1 (a < b), 0 (a == b), or 1 (a > b).
It seems like __cmp__ was deprecated since Python 3 in favor of defining __eq__, __lt__, __le__, __gt__, and _ge__ methods separately.
I defined __eq__ and __lt__ assuming that the default values for __le__ would look something like return a == b or a < b. It seems to be not the case with the following 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
And I get this outcome:
>>> 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()
This has left me to conclude that I'll have to define all the comparison magic methods manually to make a class comparable. Is there any better way?
Why has __cmp__ been deprecated? That seems like a much nicer way to deal with it
回答1:
For two objects a and b, __cmp__ requires that one of a < b, a == b, and a > b is true. But that might not be the case: consider sets, where it's very common that none of those are true, e.g. {1, 2, 3} vs {4, 5, 6}.
So __lt__ and the likes were introduced. But that left Python with two separate ordering mechanisms, which is kind of ridiculous, so the less flexible one was removed in Python 3.
You don't actually have to implement all six comparison methods. You can use the functools.total_ordering class decorator to help define the rest of the magic comparison methods:
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
来源:https://stackoverflow.com/questions/52027891/to-make-objects-of-a-custom-class-comparable-is-it-enough-to-define-just-a-few