Puisque Python ne fournit pas de versions gauche / droite de ses opérateurs de comparaison, comment décide-t-il quelle fonction appeler?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
Cela semble appeler les deux __eq__
fonctions.
Je recherche l'arbre de décision officiel.
la source
__eq__
uniquement sur l'instance d'un type n'est pas suffisant pour que == soit remplacé?J'écris une réponse mise à jour pour Python 3 à cette question.
Il est généralement entendu, mais pas toujours le cas, qui
a == b
invoquea.__eq__(b)
, outype(a).__eq__(a, b)
.Explicitement, l'ordre d'évaluation est:
b
le type de s est une sous-classe stricte (pas du même type) dua
type de s et a un__eq__
, appelez-le et renvoyez la valeur si la comparaison est implémentée,a
a__eq__
, appelez et le retourner si la comparaison est mise en œuvre,__eq__
et qu'il l'a, puis appelez-le et retournez-le si la comparaison est implémentée,is
.Nous savons si une comparaison n'est pas implémentée si la méthode retourne
NotImplemented
.(Dans Python 2, il y avait une
__cmp__
méthode qui a été recherchée, mais elle était obsolète et supprimée dans Python 3.)Testons nous-mêmes le comportement du premier contrôle en laissant B sous-classe A, ce qui montre que la réponse acceptée est fausse sur ce compte:
qui ne s'imprime
B __eq__ called
qu'avant le retourFalse
.Comment connaissons-nous cet algorithme complet?
Les autres réponses ici semblent incomplètes et obsolètes, je vais donc mettre à jour les informations et vous montrer comment vous pouvez rechercher cela par vous-même.
Ceci est géré au niveau C.
Nous devons examiner deux bits de code différents ici - le code par défaut
__eq__
pour les objets de classeobject
et le code qui recherche et appelle la__eq__
méthode, qu'elle utilise la méthode par défaut__eq__
ou personnalisée.Défaut
__eq__
La recherche
__eq__
dans les documents pertinents de l'API C nous montre ce qui__eq__
est géré partp_richcompare
- qui dans la"object"
définition de type danscpython/Objects/typeobject.c
est défini dansobject_richcompare
pourcase Py_EQ:
.Donc ici, si
self == other
nous retournonsTrue
, sinon nous retournons l'NotImplemented
objet. Il s'agit du comportement par défaut pour toute sous-classe d'objets qui n'implémente pas sa propre__eq__
méthode.Comment
__eq__
est appeléEnsuite, nous trouvons la documentation de l'API C, la fonction PyObject_RichCompare , qui appelle
do_richcompare
.Ensuite, nous voyons que la
tp_richcompare
fonction, créée pour la"object"
définition C est appelée pardo_richcompare
, alors regardons cela d'un peu plus près.Le premier contrôle dans cette fonction concerne les conditions des objets comparés:
__eq__
méthode,puis appelez la méthode de l'autre avec les arguments permutés, renvoyant la valeur si elle est implémentée. Si cette méthode n'est pas implémentée, nous continuons ...
Ensuite, nous voyons si nous pouvons rechercher la
__eq__
méthode à partir du premier type et l'appeler. Tant que le résultat n'est pas NotImplemented, c'est-à-dire qu'il est implémenté, nous le renvoyons.Sinon, si nous n'avons pas essayé la méthode de l'autre type et qu'elle est là, nous l'essayons, et si la comparaison est implémentée, nous la renvoyons.
Enfin, nous obtenons une solution de secours au cas où elle ne serait pas implémentée pour l'un ou l'autre type.
Le repli vérifie l'identité de l'objet, c'est-à-dire s'il s'agit du même objet au même endroit en mémoire - c'est le même contrôle que pour
self is other
:Conclusion
Dans une comparaison, nous respectons d'abord l'implémentation de la sous-classe de la comparaison.
Ensuite, nous tentons la comparaison avec l'implémentation du premier objet, puis avec la seconde s'il n'a pas été appelé.
Enfin, nous utilisons un test d'identité pour comparer l'égalité.
la source