Python, sollte ich den Operator __ne __ () basierend auf __eq__ implementieren?
Habe ich eine Klasse, wo ich überschreiben möchten __eq__()
Betreiber. Es scheint Sinn zu machen, dass ich Sie überschreiben sollten, die __ne__()
Betreiber so gut, aber macht es Sinn zu implementieren __ne__
basierend auf __eq__
als solche?
class A:
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
Oder gibt es etwas, das mir fehlt mit der Art, wie Python verwendet diese Operatoren, macht das nicht eine gute Idee?
InformationsquelleAutor der Frage Falmarri | 2010-12-04
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ja, das ist völlig in Ordnung. In der Tat, die Dokumentation fordert Sie zu definieren
__ne__
beim definieren__eq__
:In vielen Fällen (wie diesem), wird es einfach sein, negiert das Ergebnis der
__eq__
aber nicht immer.InformationsquelleAutor der Antwort Daniel DiPaolo
Kurze Antwort: Nein. Verwenden
==
statt der__eq__
In Python 3,
!=
ist die negation der==
standardmäßig, so dass Sie selbst dann nicht erforderlich, schreiben einen__ne__
und die Dokumentation ist nicht mehr rechthaberisch auf das schreiben ein. Aber Bedenken Sie Raymond Hettinger Kommentar:Auch, wenn Sie müssen Ihren code in Python 2, befolgen Sie die Empfehlung für Python 2 und es funktioniert auch in Python 3 nur in Ordnung.
In Python 2 definieren Sie die
__ne__
im Hinblick auf==
statt der__eq__
.E. G.
Den Beweis sehen, dass
__ne__()
operator basiert auf__eq__
und__ne__
in Python 2 auf allefalsche Verhalten in der Demo unten.
Lange Antwort
Den Dokumentation für Python 2 sagt:
So, dass bedeutet, dass, wenn wir definieren
__ne__
im Hinblick auf die inverse von__eq__
können wir ein konsistentes Verhalten.In diesem Abschnitt der Dokumentation wurde aktualisiert, für Python 3:
und in der "was ist neu" - Sektionsehen wir dieses Verhalten geändert hat:
Für die Umsetzung
__ne__
verwenden wir lieber die==
Betreiber anstatt die__eq__
- Methode direkt, so dass, wennself.__eq__(other)
einer Unterklasse zurückNotImplemented
für den Typ-geprüft, Python entsprechend zu überprüfenother.__eq__(self)
Aus der Dokumentation:Die
NotImplemented
ObjektGegeben, wenn eine reiche Vergleichsoperator, wenn Sie nicht die gleiche Art, Python überprüft, ob die
other
ist ein Subtyp, und wenn es hat, dass der Betreiber definiert, verwendet es dieother
's Methode zuerst (umgekehrte für<
<=
>=
und>
). WennNotImplemented
zurückgegeben wird, dann es nutzt die entgegengesetzte Methode. (Es tut nicht check für dieselbe Methode zweimal.) Mit der==
operator ermöglicht, diese Logik zu erfolgen.Erwartungen
Semantisch, Sie implementieren sollten
__ne__
im Hinblick auf die Prüfung auf Gleichheit, weil die Benutzer Ihrer Klasse erwarten, dass die folgenden Funktionen gleichwertig für alle Instanzen A.:Ist, die beiden oben beschriebenen Funktionen sollten immer das gleiche Ergebnis zurückgeben. Aber dies ist abhängig von der Programmierer, wie Python selbst nicht automatisch umgesetzt, ein Vorgang in Begriffen eines anderen.
Demonstration von unerwartetem Verhalten beim definieren von
__ne__
basierend auf__eq__
:Zuerst das setup:
Instantiate non-equivalent-Instanzen:
Erwartetes Verhalten:
(Hinweis: während jede zweite Behauptung der jede der unten gleichwertig ist und daher logischerweise überflüssig vor, ich bin auch Ihnen zu zeigen, dass Reihenfolge spielt keine Rolle, wenn man eine Unterklasse der anderen.)
Diese Instanzen haben
__ne__
umgesetzt mit==
:Diesen Fällen die Prüfung unter Python 3, auch korrekt funktioniert:
Und daran erinnern, dass diese
__ne__
umgesetzt mit__eq__
- dies ist zwar das erwartete Verhalten, die Implementierung ist falsch:Unerwartetes Verhalten:
Beachten Sie, dass in diesem Vergleich widerspricht die Vergleiche oben (
not wrong1 == wrong2
).und
Nicht überspringen
__ne__
in Python 2Für den Nachweis, dass Sie sollten nicht überspringen Sie die Umsetzung
__ne__
in Python 2 finden Sie im folgenden äquivalenten Objekte:Dem obigen Ergebnis sollte
False
!Python 3 Quelle
Den CPython-Implementierung ist in
typobject.c
:InformationsquelleAutor der Antwort Aaron Hall
Nur für das Protokoll, eine kirchenrechtlich korrekte und cross-Py2/Py3 portable
__ne__
würde wie folgt Aussehen:Dieser funktioniert mit jedem
__eq__
Sie definieren können, und im Gegensatz zunot (self == other)
nicht stören einige ärgerliche/komplexe Fälle, in denen Vergleiche zwischen den Fällen, in denen eine Instanz einer Unterklasse der anderen. Wenn Ihr__eq__
nichtNotImplemented
gibt, das funktioniert (mit sinnlosen overhead), wenn es nichtNotImplemented
manchmal, diese verarbeitet es richtig. Und die Python-version-check bedeutet, dass wenn die Klasseimport
-ed in Python 3,__ne__
ist undefiniert, so dass Python der nativen, effiziente fallback__ne__
Durchführung (C-version der oben genannten) zu übernehmen.InformationsquelleAutor der Antwort ShadowRanger
Kurze Antwort: ja (aber Lesen Sie die Dokumentation, um es richtig zu machen)
Zwar interessant, Aaron Hall ' s Antwort ist nicht die richtige Art und Weise zu implementieren, die
__ne__
Methode, denn mit dernot self == other
Umsetzung, die__ne__
Methode des anderen Operanden ist nie in Betracht gezogen. Im Gegensatz dazu, wie unten gezeigt, die Standard-Python-3 Umsetzung der__ne__
Methode, einen Operanden hat fallback auf die__ne__
Methode des anderen Operanden durch RücksendungNotImplemented
wenn seine__eq__
Methode gibtNotImplemented
. ShadowRanger gab die korrekte Umsetzung der__ne__
Methode:Implementierung der Vergleichsoperatoren
Den Python Language Reference für Python 3 Staaten in Ihrer Kapitel III Daten-Modell:
Übersetzt diese in Python-code (
operator_eq
für==
operator_ne
für!=
operator_lt
für<
operator_gt
für>
operator_le
für<=
undoperator_ge
für>=
):Default-Implementierung des Vergleichs von Methoden
Die Dokumentation fügt hinzu:
Die default-Implementierung der Methoden-Vergleich (
__eq__
__ne__
__lt__
__gt__
__le__
und__ge__
) somit gegeben durch:So ist dies die korrekte Umsetzung der
__ne__
Methode. Und es nicht immer wieder die inverse der__eq__
Methode, weil, wenn die__eq__
Methode gibtNotImplemented
dessen Kehrwertnot NotImplemented
istFalse
(wiebool(NotImplemented)
istTrue
) statt der gewünschtenNotImplemented
.Fehlerhafte Implementierungen von
__ne__
Als Aaron Hall oben gezeigt,
not self.__eq__(other)
ist nicht die korrekte Umsetzung der__ne__
Methode. Aber noch istnot self == other
. Letztere ist unten gezeigt durch Vergleich des Verhaltens der Standard-Implementierung mit dem Verhalten dernot self == other
Umsetzung in zwei Fällen:__eq__
Methode gibtNotImplemented
;__eq__
- Methode gibt einen Wert Verschieden vonNotImplemented
.Default-Implementierung
Lassen Sie uns sehen, was passiert, wenn die
A.__ne__
Methode verwendet die Standard-Implementierung und dieA.__eq__
Methode gibtNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
AnrufeA.__eq__
.A.__eq__
zurückNotImplemented
.!=
AnrufeB.__ne__
.B.__ne__
zurück"B.__ne__"
.Dies zeigt, dass, wenn die
A.__eq__
Methode gibtNotImplemented
dieA.__ne__
Methode fällt wieder auf dieB.__ne__
Methode.Nun wollen wir sehen, was passiert, wenn die
A.__ne__
Methode verwendet die Standard-Implementierung und dieA.__eq__
- Methode gibt einen Wert Verschieden vonNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
AnrufeA.__eq__
.A.__eq__
zurückTrue
.!=
zurücknot True
das istFalse
.Dies zeigt, dass in diesem Fall die
A.__ne__
Methode liefert das inverse derA.__eq__
Methode. So ist die__ne__
Methode verhält sich wie angekündigt in der Dokumentation.Überschreiben der Standardimplementierung der
A.__ne__
Methode mit der korrekten Umsetzung oben angegeben liefert die gleichen Ergebnisse.not self == other
UmsetzungLassen Sie uns sehen, was passiert, wenn das überschreiben der default-Implementierung des
A.__ne__
Methode mit dernot self == other
Umsetzung und dieA.__eq__
Methode gibtNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
Anrufe==
.==
AnrufeA.__eq__
.A.__eq__
zurückNotImplemented
.==
AnrufeB.__eq__
.B.__eq__
zurückNotImplemented
.==
zurückA() is B()
das istFalse
.A.__ne__
zurücknot False
das istTrue
.Die default-Implementierung der
__ne__
Methode zurückgegeben"B.__ne__"
nichtTrue
.Nun wollen wir sehen, was passiert, wenn das überschreiben der default-Implementierung des
A.__ne__
Methode mit dernot self == other
Umsetzung und dieA.__eq__
- Methode gibt einen Wert Verschieden vonNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
Anrufe==
.==
AnrufeA.__eq__
.A.__eq__
zurückTrue
.A.__ne__
zurücknot True
das istFalse
.Die default-Implementierung der
__ne__
Methode auch zurückgegebenFalse
in diesem Fall.Da diese Umsetzung scheitert repliziert das Verhalten der Standardimplementierung der
__ne__
- Methode, wenn die__eq__
Methode gibtNotImplemented
ist es falsch.InformationsquelleAutor der Antwort Maggyero
Wenn alle
__eq__
__ne__
__lt__
__ge__
__le__
und__gt__
Sinn machen für die Klasse, dann nur umsetzen__cmp__
statt. Ansonsten, tun, was Sie tun, denn die bit-Daniel DiPaolo gesagt (und ich war es zu testen, anstatt sich zu erwärmen 😉 )InformationsquelleAutor der Antwort Karl Knechtel