Python "en" opérateur: utilise l'égalité ou l'identité?

class A(object):
    def __cmp__(self):
        print '__cmp__'
        return object.__cmp__(self)

    def __eq__(self, rhs):
        print '__eq__'
        return True
a1 = A()
a2 = A()
print a1 in set([a1])
print a1 in set([a2])

pourquoi la première ligne imprime vrai, mais la seconde imprime faux? Et aucun n'entre l'opérateur eq ?

j'utilise Python 2.6

29
demandé sur Gennadiy Rozental 2012-02-01 05:10:59

5 réponses

vous devez définir __hash__ aussi. Par exemple

class A(object):
    def __hash__(self):
        print '__hash__'
        return 42

    def __cmp__(self, other):
        print '__cmp__'
        return object.__cmp__(self, other)

    def __eq__(self, rhs):
        print '__eq__'
        return True

a1 = A()
a2 = A()
print a1 in set([a1])
print a1 in set([a2])

fonctionnera comme prévu.

en règle générale, chaque fois que vous mettez en œuvre __cmp__ vous devez mettre en œuvre un __hash__ tel que pour tous x et y tel que x == y , x.__hash__() == y.__hash__() .

15
répondu David Wolever 2018-08-24 08:11:08

Set __contient__ vérifie dans l'ordre suivant:

 'Match' if hash(a) == hash(b) and (a is b or a==b) else 'No Match'

le code source C correspondant est dans Objects/setobject.c:: set_lookkey() et dans Objects/object.C:: PyObject_RichCompareBool ().

14
répondu Raymond Hettinger 2012-02-01 05:21:14

Ensembles et les dictionnaires de gagner leur vitesse à l'aide de "151920920 de" hachage comme une rapide approximation de la pleine égalité de vérification. Si vous voulez redéfinir l'égalité, vous avez généralement besoin de redéfinir l'algorithme de hachage de sorte qu'il est cohérent.

la fonction de hachage par défaut utilise l'identité de l'objet, ce qui est assez inutile comme une approximation rapide de pleine égalité, mais au moins vous permet d'utiliser une instance de classe arbitraire comme une clé de dictionnaire et de récupérer la valeur stockée avec elle si vous passer exactement le même objet que d'une clé. Mais cela signifie que si vous redéfinissez l'égalité et ne pas redéfinir la fonction de hachage, vos objets vont dans un dictionnaire/ensemble sans se plaindre de ne pas être hachable, mais ne fonctionnera toujours pas la façon dont vous attendez d'eux.

Voir l'officiel de python docs sur __hash__ pour plus de détails.

7
répondu Ben 2012-02-01 01:19:32
Les ensembles

semblent utiliser des codes de hachage, puis l'identité, avant de comparer pour l'égalité. Le code suivant:

class A(object):
    def __eq__(self, rhs):
        print '__eq__'
        return True
    def __hash__(self):
        print '__hash__'
        return 1

a1 = A()
a2 = A()

print 'set1'
set1 = set([a1])

print 'set2'
set2 = set([a2])

print 'a1 in set1'
print a1 in set1

print 'a1 in set2'
print a1 in set2

sorties:

set1
__hash__
set2
__hash__
a1 in set1
__hash__
True
a1 in set2
__hash__
__eq__
True

ce qui se passe semble être:

  1. le code de hachage est calculé lorsqu'un élément est inséré dans un hachage. (À comparer avec les éléments existants.)
  2. le code de hachage de l'objet que vous vérifiez avec l'opérateur in est calculé.
  3. les éléments de l'ensemble avec le même code de hachage sont inspectés en vérifiant d'abord s'ils sont le même objet que celui que vous recherchez, ou s'ils sont logiquement égaux à celui-ci.
0
répondu millimoose 2012-02-01 01:30:31