2012-08-07 45 views
5

¿Cuál es la forma más natural de completar el siguiente código?¿Cómo se manejan los tipos mixtos cuando se implementan operadores de comparación?

import functools 

@functools.total_ordering 
class X: 
    def __init__(self, a): 
     self._a = a 

    def __eq__(self, other): 
     if not isinstance(other, X): 
      return False 
     return self._a == other._a 

    def __lt__(self, other): 
     if not isinstance(other, X): 
      return ...     // what should go here? 
     return self._a < other._a 

if __name__ == '__main__': 
    s = [2, 'foo', X(2)] 
    s.sort() 
    print s 

Respuesta

2

Puede elegir lo que sea más natural para usted; False significa que sus instancias siempre ordenan después de otros tipos, True y se ordenarán antes.

Alternativamente, puede volver NotImplemented (ver the __lt__ and other comparison methods documentation) para señalar que la comparación no es compatible:

def __lt__(self, other): 
    if not isinstance(other, X): 
     return NotImplemented 
    return self._a < other._a 

Citando la documentación:

Un método de comparación ricos pueden devolver el producto único NotImplemented si no implementa la operación para un par de argumentos dado. Por convención, se devuelven False y True para una comparación exitosa. Sin embargo, estos métodos pueden devolver cualquier valor, por lo que si el operador de comparación se usa en un contexto booleano (por ejemplo, en la condición de una instrucción if), Python llamará al bool() para determinar si el resultado es verdadero o falso.

+1

Simplemente regresar Falso o Verdadero no es una buena idea. Considere el caso cuando tiene otra clase Y análoga y hace X ('foo') X ('foo'). Los resultados pueden no ser consistentes. – user763305

+1

Pero el regreso de NotImplemented funciona. Entonces Python usará su propio orden predeterminado que es algo arbitrario pero consistente. – user763305

4

Mi enfoque personal:

una excepción.

No hay un orden natural entre los diferentes tipos.

El oficial: (elegir éste, no debería haber)

Aunque no estoy de acuerdo con eso por completo, el manual establece claramente la forma en que debe hacerse:

http://docs.python.org/library/stdtypes.html#comparisons

Objetos de diferentes tipos, excepto diferentes tipos numéricos y diferentes tipos de cadenas, nunca se comparan iguales; tales objetos se ordenan de manera consistente pero arbitraria (de modo que ordenar una matriz heterogénea produce un resultado consistente). Además, algunos tipos (por ejemplo, objetos de archivo ) admiten solo una noción de comparación degenerada donde dos objetos de ese tipo son desiguales. De nuevo, tales objetos se ordenan de forma arbitraria pero consistente. Los operadores <, < =,> y> = generarán una excepción TypeError cuando cualquier operando sea un número complejo.

Así que, básicamente, plantearía una excepción, pero la forma más pitónica de hacer el pedido sería cumplir con el manual.

Debería haber una, y preferiblemente solo una, forma obvia de hacerlo.

+0

Pero Python implementa tal orden. Puedo ordenar la lista [2.3, 'foo', int]. – user763305

+0

'1> 'a string'' es False,' 1 <' a string'' es True. –

+0

Específicamente, 'TypeError (" no se puede comparar {} a {} ". Format (type (self), type (other)))'. – ecatmur

Cuestiones relacionadas