Python Equivalent of Java's compareTo()
I'm Doing a Project in Python (3.2) for Which I Need to Compare User Defined Objects. I'm Used to Oop in Java, Where One Would Define a compareTo() Method in...
I'm doing a project in Python (3.2) for which I need to compare user defined objects. I'm used to OOP in Java, where one would define a compareTo() method in the class that specifies the natural ordering of that class, as in the example below:
public class Foo {
int a, b;
public Foo(int aa, int bb) {
a = aa;
b = bb;
}
public int compareTo(Foo that) {
// return a negative number if this < that
// return 0 if this == that
// return a positive number if this > that
if (this.a == that.a) return this.b - that.b;
else return this.a - that.a;
}
}
I'm fairly new to classes/objects in Python, so I'd like to know what is the "pythonic" way to define the natural ordering of a class?
2 Answers
You can implement the special methods __lt__, __gt__ etc. to implement the default operators for custom types. See more about them in the language reference.
For example:
class Foo:
def __init__ (self, a, b):
self.a = a
self.b = b
def __lt__ (self, other):
if self.a == other.a:
return self.b < other.b
return self.a < other.b
def __gt__ (self, other):
return other.__lt__(self)
def __eq__ (self, other):
return self.a == other.b and self.b == other.b
def __ne__ (self, other):
return not self.__eq__(other)
Or as said by stranac in the comments, you can use the total_ordering decorator to save some typing:
@functools.total_ordering
class Foo:
def __init__ (self, a, b):
self.a = a
self.b = b
def __lt__ (self, other):
if self.a == other.a:
return self.b < other.b
return self.a < other.b
def __eq__ (self, other):
return self.a == other.b and self.b == other.b
Python has a similar function: __cmp__().
I now see you're asking about Python 3. Their "whats new" suggests:
The cmp() function should be treated as gone, and the __cmp__() special method is no longer supported. Use __lt__() for sorting, __eq__() with __hash__(), and other rich comparisons as needed. (If you really need the cmp() functionality, you could use the expression (a > b) - (a < b) as the equivalent for cmp(a, b).)
So it seems you could always do something like
def compareTo(self, that):
return ((self > that) - (self < that))
or
@classmethod
def compare(cls, a, b):
return ((a > b) - (a < b))
after implementing __gt__() and __lt__().
Which you would then use like:
f1 = Foo(1,1)
f2 = Foo(2,2)
f1.compareTo(f2)
Foo.compare(f1,f2)
This would give you equivalent functionality.