When implementing the __eq__ and __lt__ methods of a class, it is common practice to use tuples to group the values you wish to compare, like so:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (self.c, self.a, self.b) == (other.c, other.a, other.b)
def __lt__(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
However this uses the natural ordering of each key. What if I want to change, for example, how a sorts?
This is what I've come up with so far, and while it seems to work OK, I was wondering if there is a better way to go about it:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = MyA(a) # Note
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (self.c, self.a, self.b) == (other.c, other.a, other.b)
def __lt__(self, other):
return (self.c, self.a, self.b) < (other.c, other.a, other.b)
class MyA(A):
def __hash__(self):
# ...
def __eq__(self, other):
# ...
def __lt__(self, other):
# ...
Subclassing A lets me define my custom ordering, and allows MyA to behave like a regular A in every other way which is nice, but it seems wasteful / needlessly verbose especially if I have to do this for multiple fields.
Edit: As per user1320237's answer below, this is what I've come up with:
@total_ordering
class Foo(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __hash__(self):
return hash((self.c, self.a, self.b))
def __eq__(self, other):
return (0, 0, 0) == (cmp(self.c, other.c),
cmpA(self.a, other.a),
cmp(self.b, other.b))
def __lt__(self, other):
return (0, 0, 0) > (cmp(self.c, other.c),
cmpA(self.a, other.a),
cmp(self.b, other.b))
def cmpA(a1, a2):
# ...
(Note the > in __lt__ since cmp(x, y) returns -1 if x < y and __lt__ should return True)