web-dev-qa-db-fra.com

Rendre une classe python utilisateur triable, hashable

Quelles méthodes doivent être remplacées/implémentées pour rendre des classes définies par l'utilisateur pouvant être triées et/ou décomposables en python?

Quels sont les pièges à surveiller?

Je tape dir({}) dans mon interprète pour obtenir une liste de méthodes sur les dict intégrés. Parmi ceux-ci, je suppose que je dois implémenter un sous-ensemble de

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

Existe-t-il une différence entre les méthodes à implémenter pour Python3 et celles pour Python2?

56
Matt Fenwick

J'ai presque posté ceci comme un commentaire aux autres réponses mais c'est vraiment une réponse en soi.

Pour que vos articles puissent être triés, ils doivent seulement implémenter __lt__. C'est la seule méthode utilisée par le type intégré.

Les autres comparaisons ou functools.total_ordering ne sont nécessaires que si vous voulez réellement utiliser les opérateurs de comparaison avec votre classe.

Pour rendre vos éléments passibles, vous implémentez __hash__ comme d’autres l’a noté. Vous devez également implémenter __eq__ de manière compatible - les éléments équivalents doivent avoir le même hachage.

63
agf

Il n'y a pas de différence entre Python 2 et 3.

Pour la triabilité:

Vous devez définir des méthodes de comparaison. Cela rend vos articles triables. Généralement, vous ne devriez pas préférer __cmp__().

J'utilise habituellement functools.total_ordering decorator.

functools.total_ordering (cls) Dans une classe définissant une ou plusieurs méthodes de classement riches, ce décorateur de classe fournit le reste. Cela simplifie les efforts nécessaires pour spécifier toutes les opérations de comparaison enrichies possibles:

La classe doit définir l'un des éléments suivants: __lt__(), __le__(), __gt__() ou __ge__(). De plus, la classe devrait fournir une méthode __eq__().

Vous devez faire attention à ce que vos méthodes de comparaison ne génèrent aucun effet secondaire. (changer n'importe laquelle des valeurs de l'objet)

Pour le hachage:

Vous devez implémenter la méthode __hash__(). Je pense que le meilleur moyen est de retourner hash(repr(self)) afin que votre hash soit unique.

16
utdemir

Il existe plusieurs façons de marquer votre objet comme pouvant être trié. Première comparaison - riche, définie par un ensemble de fonctions:

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

De plus, il est possible de définir une seule fonction:

object.__cmp__(self, other)

Et le dernier doit être défini si vous souhaitez définir une fonction __hash__ personnalisée. Voir le doc .

2
Roman Bodnarchuk

La méthode Implement __lt__(self,other) est la solution pour rendre votre classe triable.
Il peut être utilisé non seulement pour la méthode intégrée sorted(iterable), mais également pour la file d'attente prioritaire via le module heapq.

De plus, je n'aime pas le design de python, tant de méthodes '__ge__', '__gt__', '__le__', '__lt__', '__ne__' sont pas intuitives du tout!
En revanche, le Interface Comparable<T> de Java (voir Java doc ) renvoie un entier négatif, zéro ou un entier positif, cet objet étant inférieur, égal ou supérieur à l'objet spécifié, qui est direct et convivial!

0
yichudu