Wie entscheidet Python, welche Funktion aufgerufen werden soll, da Python keine Links / Rechts-Versionen seiner Vergleichsoperatoren bereitstellt?
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
Dies scheint beide __eq__
Funktionen aufzurufen .
Ich suche den offiziellen Entscheidungsbaum.
quelle
__eq__
nur für die Instanz eines Typs zu definieren, um == zu überschreiben?Ich schreibe eine aktualisierte Antwort für Python 3 auf diese Frage.
Es wird allgemein verstanden, aber nicht immer der Fall, dass
a == b
aufrufta.__eq__(b)
, odertype(a).__eq__(a, b)
.Die Reihenfolge der Bewertung lautet explizit:
b
der Typ eine strikte Unterklasse (nicht derselbe Typ) desa
Typs ist und einen hat__eq__
, rufen Sie ihn auf und geben Sie den Wert zurück, wenn der Vergleich implementiert ist.a
hat__eq__
es nennen , und es zurückgeben , wenn der Vergleich durchgeführt wird,__eq__
und es hat, und rufen Sie es auf und geben Sie es zurück, wenn der Vergleich implementiert ist.is
.Wir wissen, ob kein Vergleich implementiert ist, wenn die Methode zurückgegeben wird
NotImplemented
.(In Python 2 gab es eine
__cmp__
Methode gesucht, die in Python 3 jedoch veraltet und entfernt wurde.)Testen wir das Verhalten der ersten Prüfung für uns selbst, indem wir B Unterklasse A lassen, was zeigt, dass die akzeptierte Antwort in dieser Hinsicht falsch ist:
die nur
B __eq__ called
vor der Rückkehr gedruckt wirdFalse
.Woher kennen wir diesen vollständigen Algorithmus?
Die anderen Antworten hier scheinen unvollständig und veraltet zu sein, daher werde ich die Informationen aktualisieren und Ihnen zeigen, wie Sie dies selbst nachschlagen können.
Dies wird auf der C-Ebene behandelt.
Wir müssen uns hier zwei verschiedene Codebits ansehen - den Standard
__eq__
für Klassenobjekteobject
und den Code, der die__eq__
Methode nachschlägt und aufruft , unabhängig davon, ob sie den Standard__eq__
oder einen benutzerdefinierten Code verwendet .Standard
__eq__
Blick nach
__eq__
oben in der entsprechenden C API - Dokumentation zeigt uns , dass__eq__
durch umgegangen wirdtp_richcompare
- die in der"object"
Typdefinition incpython/Objects/typeobject.c
in definiert istobject_richcompare
fürcase Py_EQ:
.Wenn
self == other
wir also zurückkehrenTrue
, geben wir dasNotImplemented
Objekt zurück. Dies ist das Standardverhalten für jede Unterklasse von Objekten, die keine eigene__eq__
Methode implementiert .Wie
__eq__
wird gerufenDann finden wir die C-API-Dokumente, die PyObject_RichCompare- Funktion, die aufruft
do_richcompare
.Dann sehen wir, dass die
tp_richcompare
für die"object"
C-Definition erstellte Funktion von aufgerufen wirddo_richcompare
. Schauen wir uns das also etwas genauer an.Die erste Überprüfung in dieser Funktion betrifft die Bedingungen, unter denen die Objekte verglichen werden:
__eq__
Methode:Rufen Sie dann die Methode des anderen mit vertauschten Argumenten auf und geben Sie den Wert zurück, falls implementiert. Wenn diese Methode nicht implementiert ist, fahren wir fort ...
Als nächstes sehen wir, ob wir die
__eq__
Methode vom ersten Typ an nachschlagen und aufrufen können. Solange das Ergebnis nicht NotImplemented ist, dh implementiert ist, geben wir es zurück.Andernfalls versuchen wir es, wenn wir die Methode des anderen Typs nicht ausprobiert haben und sie vorhanden ist. Wenn der Vergleich implementiert ist, geben wir sie zurück.
Schließlich erhalten wir einen Fallback für den Fall, dass er für keinen der beiden Typen implementiert ist.
Der Fallback prüft auf die Identität des Objekts, dh ob es sich um dasselbe Objekt an derselben Stelle im Speicher handelt. Dies ist dieselbe Prüfung wie für
self is other
:Fazit
In einem Vergleich respektieren wir zuerst die Unterklassenimplementierung des Vergleichs.
Dann versuchen wir den Vergleich mit der Implementierung des ersten Objekts, dann mit der des zweiten Objekts, wenn es nicht aufgerufen wurde.
Schließlich verwenden wir einen Identitätstest zum Vergleich auf Gleichheit.
quelle