112 votes

Comment mettre en place une bonne __hash__ fonction en python

Lors de l'implémentation d'une classe avec plusieurs propriétés (comme dans le jouet exemple ci-dessous), ce qui est la meilleure façon de gérer le hachage?

Je suppose que l' __eq__ et __hash__ doit être constante, mais comment mettre en place une bonne fonction de hachage qui est capable de traiter toutes les propriétés?

class AClass:
  def __init__(self):
      self.a = None
      self.b = None

  def __eq__(self, other):
      return other and self.a == other.a and self.b == other.b

  def __ne__(self, other):
    return not self.__eq__(other)

  def __hash__(self):
      return hash((self.a, self.b))

J'ai lu sur cette question que les tuples sont hashable, donc je me demandais si quelque chose comme l'exemple ci-dessus a été sensible. S'agit-il?

87voto

adw Points 2209

__hash__ doit retourner la même valeur pour les objets qui sont égaux. Il ne devrait pas changer au cours de la durée de vie de l'objet; en général, vous n'en œuvre pour des objets immuables.

Une implémentation simple serait de simplement return 0. C'est toujours correct, mais qui joue mal.

Votre solution, le retour de la valeur de hachage d'un tuple de propriétés, est bon. Mais notez que vous n'avez pas besoin de liste de toutes les propriétés que vous comparez en __eq__ dans le tuple. Si une propriété a généralement la même valeur pour inégalitaires des objets, il suffit de laisser sortir. Ne faites pas le calcul de hachage plus cher qu'il ne devrait l'être.

Edit: je déconseille l'utilisation de xor pour mélanger les hachages en général. Lorsque deux propriétés ont la même valeur, ils ont le même hash, et avec xor ces va s'annuler mutuellement. Les Tuples utiliser un calcul plus complexe à mélanger les hachages, voir tuplehash en tupleobject.c.

18voto

S.Lott Points 207588

La Documentation de l'objet.de hachage(auto)

La seule propriété est que les objets qui permettent de comparer l'égalité ont la même valeur de hachage, il est conseillé de faire en quelque sorte mélanger (par exemple à l'aide de ou exclusif) les valeurs de hachage pour les composants de l'objet qui jouent également un rôle dans la comparaison d'objets.

def __hash__(self):
    return hash(self.a) ^ hash(self.b)

17voto

max Points 6673

Il est dangereux d'écrire

def __eq__(self, other):
  return other and self.a == other.a and self.b == other.b

parce que si votre rhs (c'est à dire, other) de l'objet renvoie la valeur booléenne False, il ne sera jamais considérées comme égales à rien!

En outre, vous pouvez vérifier si other appartient à la classe ou sous-classe d' AClass. Si ça ne marche pas, vous pourrez soit obtenir exception AttributeError ou un faux positif (si l'autre classe arrive à avoir le même nom d'attributs avec des valeurs correspondantes). Donc je vous conseille de réécrire __eq__ comme:

def __eq__(self, other):
  return isinstance(other, self.__class__) and self.a == other.a and self.b == other.b

Si par hasard vous voulez exceptionnellement flexible de comparaison, ce qui se compare à travers les classes indépendantes tant qu'attributs de match par nom, vous auriez encore envie pour au moins éviter d' AttributeError , et vérifier qu' other n'ont pas d'attributs supplémentaires. Comment vous faites cela dépend de la situation (car il n'y a pas de méthode standard pour trouver tous les attributs d'un objet).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X