Question

J'avais un étrange bug lors du portage d'une fonctionnalité sur la fourche Python 3.1 de mon programme. Je l'ai réduite à l'hypothèse suivante:

Contrairement à Python 2.x, dans Python 3.x, si un objet utilise une méthode __eq__, il est automatiquement soulagé.

Est-ce vrai?

Voici ce qui se passe dans Python 3.1:

>>> class O(object):
...     def __eq__(self, other):
...         return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    d = {o: 0}
TypeError: unhashable type: 'O'

La question de suivi est la suivante: comment puis-je résoudre mon problème personnel? J'ai un objet ChangeTracker qui stocke un WeakKeyDictionary pointant vers plusieurs objets, donnant pour chacun la valeur de leur vidage de cornichons à un moment donné dans le passé. Chaque fois qu'un objet existant est archivé, l'outil de suivi des modifications indique si son nouveau pickle est identique à l'ancien, indiquant donc si l'objet a changé entre-temps. Le problème, c’est que maintenant je ne peux même pas vérifier si l’objet donné se trouve dans la bibliothèque, car cela le fait lever une exception à propos de la pureté de l’objet. (Parce que sa méthode est <=>.) Comment puis-je contourner ce problème?

Était-ce utile?

La solution

Oui, si vous définissez __eq__, la valeur par défaut __hash__ (à savoir, le hachage de l'adresse de l'objet en mémoire) disparaît. Ceci est important car le hachage doit être cohérent avec l'égalité: les objets égaux doivent avoir le même hachage.

La solution est simple: définissez simplement <=> en même temps que <=>.

Autres conseils

Ce paragraphe de http://docs.python.org/3.1 /reference/datamodel.html#object. hash

  

Si une classe qui annule __eq__()   doit conserver la mise en œuvre de   __hash__() d'une classe parente, l'interprète doit être informé de cette   explicitement en définissant __hash__ = <ParentClass>.__hash__. Sinon le   l'héritage de __hash__ sera   bloqué, comme si <=> avait été   explicitement défini sur Aucun.

Consultez le manuel de Python 3 sur object.__hash__ :

  

Si une classe ne définit pas de méthode __eq__(), elle ne devrait pas non plus définir une opération __hash__(); s'il définit __hash__(self) mais pas id(self), ses instances ne seront pas utilisables en tant qu'éléments de collections à caractère amovible.

L’accent est à moi.

Si vous voulez être paresseux, il semble que vous puissiez simplement définir x.__hash__() pour renvoyer id(x):

  

Les classes définies par l'utilisateur ont <=> et <=> méthodes par défaut; avec eux, tous les objets comparent de manière inégale (sauf avec eux-mêmes) et <=> renvoie <=>.

Je ne suis pas un expert en python, mais cela n’aurait-il pas un sens que, lorsque vous définissez une méthode eq, vous devez également définir une méthode de hachage (qui calcule la valeur de hachage d'un objet), sinon, le mécanisme de hachage ne sait pas s'il frappe le même objet ou un objet différent avec la même valeur de hachage. En fait, c’est l’inverse, il faudrait probablement calculer différentes valeurs de hachage pour les objets considérés égaux par votre __eq__ méthode.

Je n'ai aucune idée du nom de cette fonction de hachage, __hash__ peut-être? :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top