2011-08-22 12 views
45

¿Qué métodos deben ser reemplazados/implementados al hacer las clases definidas por el usuario ordenables y/o hashables en python?Hacer una clase definida por el usuario de python ordenable, hashable

¿Cuáles son los problemas a tener en cuenta?

Escribo dir({}) en mi intérprete para obtener una lista de métodos en los dicts integrados. De ellos, supongo que necesito un poco de poner en práctica algún subconjunto de

['__cmp__', '__eq__', '__ge__', '__gt__', '__hash__', '__le__', '__lt__', '__ne__'] 

¿Hay alguna diferencia en que los métodos deben ser implementados por python3 en contraposición a python2?

+3

Buena discusión aquí: http://stackoverflow.com/q/1061283/641766. La diferencia entre Python 2.xy 3.x es que '__cmp__' fue eliminada. – zeekay

Respuesta

51

Casi publiqué esto como un comentario a las otras respuestas, pero en realidad es una respuesta en sí misma.

Para hacer que sus artículos se puedan ordenar, solo necesitan implementar __lt__. Ese es el único método utilizado por el tipo integrado.

Las otras comparaciones o functools.total_ordering solo son necesarias si realmente desea utilizar los operadores de comparación con su clase.

Para que sus elementos sean lavables, implemente __hash__ como se indica en otros. También debe implementar __eq__ de una manera compatible: los elementos que son equivalentes deberían tener el mismo hash.

+0

por lo que una implementación deficiente de '__lt__' podría hacer que python clasifique de manera impredecible? (Por ejemplo, si x .__ lt __ (y) y y .__ lt __ (x)) –

+3

no sé de "impredeciblemente", será consistente si se alimenta con la misma entrada exacta, pero un orden de entrada diferente podría causar diferente artículos para estar en un orden diferente. Sí, si implementa incorrectamente la comparación utilizada para ordenar, Python ordenará de forma incorrecta. Yo recomendaría una función '__key__' que convierta la instancia en una tupla, y luego simplemente' '__lt__' (' self .__ key __() agf

2

Hay algunas maneras de marcar su objeto ordenable. En primer lugar - rica comparación, definida por un conjunto de funciones:

object.__lt__(self, other) 
object.__le__(self, other) 
object.__eq__(self, other) 
object.__ne__(self, other) 
object.__gt__(self, other) 
object.__ge__(self, other) 

También es posible definir una única función:

object.__cmp__(self, other) 

Y el último es preciso definir si desea definir encargo __hash__ función . Vea el doc.

+1

En Python 3, "[...] el método especial' __cmp __() 'ya no es compatible," consulte la [sección pertinente aquí] (https://docs.python.org/release/3.0.1/whatsnew). /3.0.html#ordering-comparisons). –

10

no hay ninguna diferencia entre Python 2 y 3.

Para sortability:

Debe definir métodos COMPARACIÓN. Esto hace que tus artículos puedan ordenarse. En general, no debe preferir __cmp__().

suelo utilizar functools.total_ordering decorator.

functools.total_ordering (CLS) Dada una clase define una o más ricas formas de realizar pedidos de comparación, este decorador clase suministra el resto. Esto simplifica el esfuerzo involucrado en la especificación de todas las posibles operaciones de comparación ricos:

La clase debe definir uno de __lt__(), __le__(), __gt__() o __ge__(). Además, la clase debe proporcionar un método __eq__().

Debe tener cuidado con los métodos de comparación por tener efectos secundarios. No quieres que tu clase cambie cuando haces comparaciones.

para hash:

Debe implementar __hash__() método. Creo que la mejor manera es devolver hash(repr(self)), por lo que su hash sería único.

+0

Para obtener un ejemplo de 'functools.total_ordering' de la documentación, consulte [aquí] (https://docs.python.org/2/library/functools.html#functools.total_ordering). –

0

Implementar el método __lt__(self,other) es la respuesta para hacer que su clase sea ordenable.
Se puede usar no solo para el método incorporado sorted(iterable), sino también para la cola de prioridad a través del módulo heapq.

Además, no me gusta el diseño de Python, tantos '__ge__', '__gt__', '__le__', '__lt__', '__ne__' métodos son no intuitivo en absoluto!
Como contraste, Java Interface Comparable<T> (ver java doc) devuelve un entero negativo, cero o un entero positivo ya que este objeto es menor, igual o mayor que el objeto especificado, que es directa y amigable!

Cuestiones relacionadas