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
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__()
.
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 ().
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.
une réponse tangentielle, mais votre question et mes tests m'ont rendu curieux. Si vous ignorez l'opérateur d'ensemble qui est la source de votre __hash__
problème, il s'avère que votre question est intéressante.
grâce à l'aide que j'ai reçu sur cette question "so 151960920" , j'ai pu poursuivre l'opérateur in à travers le code source jusqu'à sa racine. Près du bas j'ai trouvé la fonction Pyobject_richcomprebool qui teste en effet pour l'identité (voir le commentaire à propos de "résultat Rapide") avant de tester l'égalité.
donc, à moins que je ne me méprenne sur la façon dont les choses fonctionnent, la réponse technique à votre question Est d'abord l'identité, puis l'égalité, à travers le test d'égalité lui-même. Juste pour répéter, ce n'est pas la source du comportement que vous avez vu mais juste la réponse technique à votre question.
si j'ai mal compris la source, que quelqu'un me mette au clair.
int
PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
{
PyObject *res;
int ok;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if (v == w) {
if (op == Py_EQ)
return 1;
else if (op == Py_NE)
return 0;
}
res = PyObject_RichCompare(v, w, op);
if (res == NULL)
return -1;
if (PyBool_Check(res))
ok = (res == Py_True);
else
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
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:
- le code de hachage est calculé lorsqu'un élément est inséré dans un hachage. (À comparer avec les éléments existants.)
- le code de hachage de l'objet que vous vérifiez avec l'opérateur
in
est calculé. - 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.