2012-06-26 2 views
8

Я делаю проект в Python (3.2), для которого мне нужно сравнивать объекты, определенные пользователем. Я привык к ООП в Java, где можно было бы определить метод compareTo() в классе, который определяет естественный порядок этого класса, как показано в следующем примере:Python эквивалент Java compareTo()

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; 
    } 
} 

Я довольно новыми для классов/объектов в Python, поэтому я хотел бы знать, что такое «питонический» способ определения естественного упорядочения класса?

+1

Вы имеете в виду, как [ '__cmp__'] (HTTP : //docs.python.org/reference/datamodel.html#object.__cmp__)? –

ответ

10

Вы можете реализовать специальные методы __lt__, __gt__ и т. Д. Для реализации операторов по умолчанию для пользовательских типов. Узнайте больше о них в language reference.

Например:

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) 

Или, как сказано stranac в комментариях, вы можете использовать total_ordering декоратора, чтобы сохранить некоторые набрав:

@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 
+3

Вы также можете просто определить' __lt__' и '__eq__' и использовать декоратор' functools.total_ordering'. – stranac

+1

В Python 2 '__gt__' автоматически' not __lt__', если не предоставлен (только что протестировал его). Странно, что в документации говорится иначе. Кто-то хочет протестировать его на Python 3, возможно, @stranac? – schlamar

+0

Вы правы, но возможно, что документация фактически относится только к обратному, т. Е. 'Not (a < b) == (a > = b)' (где последнее будет создавать исключение, если оно не определено), поэтому, я думаю, он меняет параметры, если это возможно. – poke

6

Python имеет аналогичную функцию: __cmp__().

теперь я вижу, что вы спрашиваете о 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).) 

Так что, похоже, вы всегда можете сделать что-то вроде

def compareTo(self, that): 
    return ((self > that) - (self < that)) 

или

@classmethod 
def compare(cls, a, b): 
    return ((a > b) - (a < b)) 

после внедрения __gt__() и __lt__().

Какой бы вы затем использовать как:

f1 = Foo(1,1) 
f2 = Foo(2,2) 

f1.compareTo(f2) 
Foo.compare(f1,f2) 

Это даст вам эквивалентную функциональность.

+3

'__cmp__' больше не существует в Python 3, а OP задает вопрос о Python 3. – poke