2012-06-26 14 views
8

Wykonuję projekt w Pythonie (3.2), dla którego muszę porównać obiekty zdefiniowane przez użytkownika. Przywykłem do OOP w Java, gdzie można by zdefiniować compareTo() metody w klasie, która określa naturalne uporządkowanie tej klasy, jak w poniższym przykładzie:Python odpowiednik Java to 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; 
    } 
} 

Jestem całkiem nowy na lekcji/przedmiotów w Pythonie, więc chciałbym wiedzieć, jaki jest "pytonowy" sposób definiowania naturalnego porządku klasy?

+1

Masz na myśli [ '__cmp__'] (http : //docs.python.org/reference/datamodel.html#object.__cmp__)? –

Odpowiedz

10

Można zaimplementować specjalne metody __lt__, __gt__ itd., Aby zaimplementować domyślne operatory dla typów niestandardowych. Zobacz więcej o nich w language reference.

Na przykład:

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) 

Albo jak powiedział stranac w komentarzach, można użyć total_ordering dekorator zaoszczędzić trochę wpisując:

@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

Można również zdefiniować' __lt__' i '__eq__' i użyć dekoratora' functools.total_ordering'. – stranac

+1

W Pythonie 2 '__gt__' jest automatycznie' nie __lt__', jeśli nie jest dostarczone (po prostu przetestowane). Dziwne, że dokumentacja mówi inaczej. Ktoś chce przetestować go na Pythonie 3, może @stranac? – schlamar

+0

Masz rację, ale może się zdarzyć, że dokumentacja faktycznie odwołuje się tylko do odwrotności, tj. 'Not (a < b) == (a > = b)' (gdzie ta ostatnia podniesie wyjątek, jeśli nie jest zdefiniowana), więc domyślam się, że to zamienia parametry, jeśli to możliwe. – poke

6

Python ma podobną funkcję: __cmp__().

widzę teraz pytasz o Pythonie 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).) 

Wydaje się więc zawsze można zrobić coś takiego

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

lub

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

po wdrożeniu __gt__() i __lt__().

Które następnie użyć jak:

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

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

To daje równoważną funkcjonalność.

+3

'__cmp__' już nie istnieje w Pythonie 3, a OP pyta o Python 3. – poke