Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 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?

like image 514
astay13 Avatar asked Jun 26 '12 21:06

astay13


People also ask

What is difference between == equals () and compareTo () method?

The equals() tells the equality of two strings whereas the compareTo() method tell how strings are compared lexicographically.

What does compareTo () do?

The compareTo() method compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. The method returns 0 if the string is equal to the other string.

What is the return type of the compareTo () function in Java?

compareTo() in java returns an integer value. It returns a positive integer if string1 is lexicographically greater than string2, negative if string2 is greater than string1, and zero if both are equal.

Is compareTo a default method?

The compareTo method defines the natural order; the default way for ordering objects 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
like image 200
poke Avatar answered Sep 16 '22 19:09

poke


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.

like image 37
jedwards Avatar answered Sep 19 '22 19:09

jedwards