2012-06-26 29 views
8

Estoy haciendo un proyecto en Python (3.2) para el cual necesito comparar objetos definidos por el usuario. Estoy acostumbrado a la POO en Java, donde se podría definir un método compareTo() en la clase que especifica el orden natural de esa clase, como en el siguiente ejemplo:Python equivalente de Java's 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; 
    } 
} 

Soy bastante nuevo a clases/objetos en Python, entonces me gustaría saber cuál es la forma "pitónica" de definir el orden natural de una clase?

+1

¿Quieres decir como [ '__cmp__'] (http : //docs.python.org/reference/datamodel.html#object.__cmp__)? –

Respuesta

10

Puede implementar los métodos especiales __lt__, __gt__ etc. para implementar los operadores predeterminados para los tipos personalizados. Ver más sobre ellos en el language reference.

Por ejemplo:

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) 

O como dijo stranac en los comentarios, puede utilizar el decorador total_ordering para ahorrar algo de mecanografía:

@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

También podría simplemente definir' __lt__' y '__eq__' y usar el decorador' functools.total_ordering'. – stranac

+1

En Python 2 '__gt__' es automáticamente' not __lt__' si no se proporciona (simplemente lo probé). Es extraño que la documentación diga lo contrario. Alguien quiere probarlo en Python 3, tal vez @stranac? – schlamar

+0

Tiene razón, pero podría ser posible que la documentación solo se refiera a la inversa, es decir, 'no (a < b) == (a > = b)' (donde esta última generará una excepción si no está definida), así que supongo que cambia la parámetros si es posible. – poke

6

Python tiene una función similar: __cmp__().

ahora veo que estás preguntando sobre 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).) 

por lo que parece que siempre se puede hacer algo como

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

o

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

después de implementar __gt__() y __lt__().

Qué usted entonces utilizar como:

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

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

Esto le daría una funcionalidad equivalente.

+3

'__cmp__' ya no existe en Python 3, y OP pregunta por Python 3. – poke