Ich habe eine Klasse, in der ich den __eq__()
Operator überschreiben möchte . Es scheint sinnvoll zu sein , dass ich das außer Kraft setzen sollte __ne__()
auch Betreiber, aber macht es Sinn, zu implementieren , __ne__
auf der Grundlage __eq__
als solche?
class A:
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
Oder fehlt mir etwas an der Art und Weise, wie Python diese Operatoren verwendet, was dies nicht zu einer guten Idee macht?
quelle
__ne__
verwenden__eq__
, nur , dass Sie es implementieren.NotImplemented
Rückgabe von einer Seite als Hinweis für die Delegierung__ne__
auf der anderen Seite zu behandeln,not self == other
wird__eq__
implizit (vorausgesetzt, der Operand weiß nicht, wie der andere Operand verglichen werden soll)__eq__
von der anderen Seite an delegiert und dann invertiert. Bei seltsamen Typen, z. B. den Feldern des SQLAlchemy ORM, verursacht dies Probleme .__ne__
automatisch an delegiert,__eq__
und das Zitat in dieser Antwort ist in den Dokumenten nicht mehr vorhanden. Unterm Strich ist es vollkommen pythonisch, nur zu implementieren__eq__
und__ne__
delegieren zu lassen .Kurze Antwort: Implementieren Sie es nicht, aber wenn Sie müssen, verwenden Sie es
==
nicht__eq__
In Python 3
!=
ist die Negation==
standardmäßig so, dass Sie nicht einmal eine schreiben müssen__ne__
, und die Dokumentation enthält keine Meinung mehr zum Schreiben einer.Im Allgemeinen schreiben Sie für Nur-Python-3-Code keinen, es sei denn, Sie müssen die übergeordnete Implementierung überschatten, z. B. für ein integriertes Objekt.
Denken Sie also an den Kommentar von Raymond Hettinger :
Wenn Sie Ihren Code benötigen, um in Python 2 zu funktionieren, befolgen Sie die Empfehlung für Python 2 und es funktioniert in Python 3 einwandfrei.
In Python 2 implementiert Python selbst keine Operation automatisch in Bezug auf eine andere - daher sollten Sie die
__ne__
in Bezug auf==
anstelle von definieren__eq__
. Z.BSiehe Beweis dafür
__ne__()
basierend auf__eq__
und__ne__
in Python 2 implementiertbietet in der folgenden Demonstration ein falsches Verhalten.
Lange Antwort
Die Dokumentation zu Python 2 lautet:
Das heißt, wenn wir
__ne__
das Gegenteil von definieren__eq__
, können wir ein konsistentes Verhalten erhalten.Dieser Abschnitt der Dokumentation wurde für Python 3 aktualisiert :
und im Abschnitt "Was ist neu" sehen wir, dass sich dieses Verhalten geändert hat:
Für die Implementierung
__ne__
bevorzugen wir die Verwendung des==
Operators anstelle der__eq__
direkten Verwendung der Methode. Wennself.__eq__(other)
eine UnterklasseNotImplemented
für den überprüften Typ zurückgibt , prüft Python dies inother.__eq__(self)
der Dokumentation entsprechend :Wenn ein reichen Vergleichsoperator gegeben, wenn sie nicht vom gleichen Typ sind, dann prüft Python , wenn das
other
ist ein Subtyp, und wenn es , dass die Betreiber definiert hat, verwendet er dieother
‚s Methode zuerst (inverse für<
,<=
,>=
und>
). WennNotImplemented
zurückgegeben wird , dann verwendet er die Methode des Gegenteils. (Es wird nicht zweimal nach derselben Methode gesucht.) Die Verwendung des==
Operators ermöglicht diese Logik.Erwartungen
Semantisch sollten Sie
__ne__
im Hinblick auf die Prüfung auf Gleichheit implementieren, da Benutzer Ihrer Klasse erwarten, dass die folgenden Funktionen für alle Instanzen von A gleichwertig sind:Das heißt, beide oben genannten Funktionen sollten immer das gleiche Ergebnis zurückgeben. Dies hängt jedoch vom Programmierer ab.
Demonstration unerwarteten Verhaltens bei der Definition
__ne__
basierend auf__eq__
:Zuerst das Setup:
Nicht äquivalente Instanzen instanziieren:
Erwartetes Verhalten:
(Hinweis: Während jede zweite Behauptung der folgenden Aussagen äquivalent und daher logisch redundant zu der vorherigen ist, füge ich sie hinzu, um zu demonstrieren, dass die Reihenfolge keine Rolle spielt, wenn eine eine Unterklasse der anderen ist. )
Diese Instanzen wurden
__ne__
implementiert mit==
:Diese Instanzen, die unter Python 3 getestet werden, funktionieren ebenfalls ordnungsgemäß:
Und denken Sie daran, dass diese
__ne__
implementiert wurden mit__eq__
- während dies das erwartete Verhalten ist, ist die Implementierung falsch:Unerwartetes Verhalten:
Beachten Sie, dass dieser Vergleich den obigen Vergleichen widerspricht (
not wrong1 == wrong2
).und,
Überspringen Sie nicht
__ne__
in Python 2Hinweise, dass Sie die Implementierung
__ne__
in Python 2 nicht überspringen sollten, finden Sie in den entsprechenden Objekten:Das obige Ergebnis sollte sein
False
!Python 3-Quelle
Die Standard-CPython-Implementierung für
__ne__
isttypeobject.c
inobject_richcompare
:Aber die Standard -
__ne__
Anwendungen__eq__
?Das Standardimplementierungsdetail von Python 3
__ne__
auf C-Ebene wird verwendet,__eq__
da die höhere Ebene==
( PyObject_RichCompare ) weniger effizient wäre - und daher auch behandelt werden mussNotImplemented
.Wenn
__eq__
es korrekt implementiert ist,==
ist auch die Negation von korrekt - und es ermöglicht uns, Implementierungsdetails auf niedriger Ebene in unserem zu vermeiden__ne__
.Mit
==
ermöglicht es uns , unsere niedriges Niveau Logik in zu halten , einen Ort, und zu vermeiden AdressierungNotImplemented
in__ne__
.Man könnte fälschlicherweise annehmen, dass dies
==
zurückkehren könnteNotImplemented
.Es verwendet tatsächlich dieselbe Logik wie die Standardimplementierung von
__eq__
, die auf Identität prüft (siehe do_richcompare und unsere Beweise unten).Und die Vergleiche:
Performance
Nehmen Sie nicht mein Wort dafür, lassen Sie uns sehen, was performanter ist:
Ich denke, diese Leistungszahlen sprechen für sich:
Dies ist sinnvoll, wenn Sie bedenken, dass
low_level_python
in Python Logik ausgeführt wird, die sonst auf C-Ebene behandelt würde.Reaktion auf einige Kritiker
Ein anderer Antwortender schreibt:
Mit
__ne__
nie RückkehrNotImplemented
macht es nicht falsch. Stattdessen behandeln wir die Priorisierung mitNotImplemented
über die Prüfung auf Gleichheit mit==
. Vorausgesetzt, es==
ist korrekt implementiert, sind wir fertig.Nun, lassen Sie uns das erklären.
Wie bereits erwähnt, behandelt Python 3 standardmäßig
__ne__
zuerst, obself.__eq__(other)
zurückgegeben wirdNotImplemented
(ein Singleton). Dies sollte überprüftis
und zurückgegeben werden, wenn dies der Fall ist. Andernfalls sollte die Umkehrung zurückgegeben werden. Hier ist diese Logik, die als Klassenmixin geschrieben wurde:Dies ist für die Korrektheit der Python-API auf C-Ebene erforderlich und wurde in Python 3 eingeführt
__ne__
Methoden in diesem Patch zum Schließen von Issue 21408 und__ne__
Methoden in der nachfolgenden Bereinigung wurden hier entferntredundant. Alle relevanten
__ne__
Methoden wurden entfernt, einschließlich derer, die ihre eigene Prüfung implementieren, sowie solcher, die__eq__
direkt oder über delegieren==
- und dies==
war die häufigste Methode.Ist Symmetrie wichtig?
Unser hartnäckiger Kritiker liefert ein pathologisches Beispiel, um die Handhabung
NotImplemented
zu__ne__
rechtfertigen und Symmetrie über alles zu bewerten. Lassen Sie uns das Argument mit einem klaren Beispiel stählern:Nach dieser Logik müssen wir also, um die Symmetrie aufrechtzuerhalten, die komplizierte
__ne__
Version unabhängig von der Python-Version schreiben .Anscheinend sollten wir uns nicht darum kümmern, dass diese Instanzen gleich und nicht gleich sind.
Ich schlage vor, dass Symmetrie weniger wichtig ist als die Annahme eines vernünftigen Codes und das Befolgen der Hinweise in der Dokumentation.
Wenn A jedoch eine vernünftige Implementierung von hätte
__eq__
, könnten wir hier immer noch meiner Richtung folgen und hätten immer noch Symmetrie:Fazit
Verwenden Sie
==
zum Implementieren von Python 2-kompatiblem Code__ne__
. Es ist mehr:In Python 3 nur, verwenden Sie die Low-Level - Negation auf der C - Ebene - es ist noch mehr einfache und performante (obwohl der Programmierer für die Bestimmung verantwortlich ist , dass es richtig ).
Schreiben Sie auch hier keine Low-Level-Logik in High-Level-Python.
quelle
a1 != c2
zurückgekehrt sindFalse
- es lief nichta1.__ne__
, aberc2.__ne__
das hat die Mixin-__eq__
Methode negiert . DaNotImplemented
ist wahr,not NotImplemented
istFalse
.not (self == other)
, aber niemand argumentiert, dass es nicht schnell ist (naja, schneller als jede andere Option auf Py2). Das Problem ist, dass es in einigen Fällen falsch ist; Python selbst hat dies früher getannot (self == other)
, sich jedoch geändert, weil es bei Vorhandensein beliebiger Unterklassen falsch war . Am schnellsten zur falschen Antwort ist immer noch falsch .__ne__
Delegierten__eq__
(bei Bedarf von beiden Seiten), aber es fällt nie auf das__ne__
der anderen Seite zurück, selbst wenn beide__eq__
"aufgeben". Die richtigen__ne__
Delegierten an sich selbst__eq__
, aber wenn dies zurückkehrtNotImplemented
, greift es zurück, um zur anderen Seite zu wechseln__ne__
, anstatt die andere Seite umzukehren__eq__
(da die andere Seite sich möglicherweise nicht explizit für die Delegierung__eq__
entschieden hat und Sie dies nicht tun sollten diese Entscheidung dafür treffen).__eq__
noch__ne__
gibt entwederTrue
oderFalse
, sondern ein Proxy - Objekt (die „truthy“ passiert zu sein). Falsches Implementieren__ne__
bedeutet, dass die Reihenfolge für den Vergleich von Bedeutung ist (Sie erhalten nur einen Proxy in einer Bestellung).__ne__
ganz weglassen können . In einem Jahr wird Py2 tot sein und wir ignorieren dies. :-)Nur zur Veranschaulichung
__ne__
: Ein kanonisch korrektes und kreuzweise tragbares Py2 / Py3-Gerät würde folgendermaßen aussehen:Dies funktioniert mit allen, die
__eq__
Sie definieren könnten:not (self == other)
stört es nicht in einigen nervigen / komplexen Fällen mit Vergleichen, in denen eine der beteiligten Klassen nicht impliziert, dass das Ergebnis von__ne__
das gleiche ist wie das Ergebnis vonnot
on__eq__
(z. B. ORM von SQLAlchemy, wo beide__eq__
und__ne__
spezielle Proxy-Objekte zurückgeben). nichtTrue
oderFalse
, und der Versuch,not
das Ergebnis von zu erhalten,__eq__
würde zurückkehrenFalse
, anstatt das richtige Proxy-Objekt).not self.__eq__(other)
wird dies korrekt an die__ne__
der anderen Instanz delegiert, wennself.__eq__
zurückgegeben wirdNotImplemented
(not self.__eq__(other)
wäre besonders falsch, daNotImplemented
es wahr ist, wenn__eq__
also nicht gewusst wird, wie der Vergleich durchgeführt werden soll,__ne__
würde dies zurückkehrenFalse
, was bedeutet, dass die beiden Objekte gleich waren , obwohl es tatsächlich das einzige war Objekt gefragt hatte keine Ahnung, was einen Ausfall von ungleich bedeuten würde)Wenn Sie
__eq__
keineNotImplemented
Retouren verwenden, funktioniert dies (mit bedeutungslosem Overhead). Wenn diesNotImplemented
manchmal verwendet wird, wird dies ordnungsgemäß behandelt. Und die Python-Versionsprüfung bedeutet, dass, wenn die Klasseimport
in Python 3 -ed__ne__
ist, undefiniert bleibt, sodass Pythons native, effiziente Fallback-__ne__
Implementierung (eine C-Version der oben genannten Version) die Kontrolle übernehmen kann.Warum das nötig ist
Python-Überladungsregeln
Die Erklärung, warum Sie dies anstelle anderer Lösungen tun, ist etwas geheimnisvoll. Python hat einige allgemeine Regeln zum Überladen von Operatoren und insbesondere zu Vergleichsoperatoren:
LHS OP RHS
Versuchen Sie es beim AusführenLHS.__op__(RHS)
, und wenn dies zurückkehrtNotImplemented
, versuchen Sie esRHS.__rop__(LHS)
. Ausnahme: WennRHS
es sich um eine Unterklasse derLHS
Klasse handelt, testen SieRHS.__rop__(LHS)
zuerst . Im Falle der Vergleichsoperatoren,__eq__
und__ne__
sind ihre eigenen „rop“ s (so der Prüfauftrag für__ne__
istLHS.__ne__(RHS)
, dannRHS.__ne__(LHS)
umgekehrt , wennRHS
eine Unterklasse von istLHS
‚s - Klasse)LHS.__eq__(RHS)
RückgabeTrue
keineLHS.__ne__(RHS)
RückgabeFalse
(tatsächlich müssen die Operatoren nicht einmal boolesche Werte zurückgeben; ORMs wie SQLAlchemy tun dies absichtlich nicht, was eine aussagekräftigere Abfragesyntax ermöglicht). Ab Python 3__ne__
verhält sich die Standardimplementierung so, ist jedoch nicht vertraglich geregelt. Sie können__ne__
auf eine Weise überschreiben , die keine strengen Gegensätze sind__eq__
.Wie dies für die Überlastung von Komparatoren gilt
Wenn Sie also einen Operator überlasten, haben Sie zwei Jobs:
NotImplemented
, damit Python an die Implementierung des anderen Operanden delegieren kannDas Problem mit
not self.__eq__(other)
delegiert niemals an die andere Seite (und ist falsch, wenn sie
__eq__
ordnungsgemäß zurückgegeben wirdNotImplemented
). Wenn Sieself.__eq__(other)
zurückkehrenNotImplemented
(was "wahr" ist), kehren Sie stillschweigend zurückFalse
, alsoA() != something_A_knows_nothing_about
kehrenFalse
Sie zurück , wenn Sie hätten prüfen sollen, ob Siesomething_A_knows_nothing_about
wissen, wie Sie mit Instanzen von vergleichen sollenA
, und wenn dies nicht der Fall ist, sollten Sie zurückkehrenTrue
(da keine Seite weiß, wie im Vergleich zu den anderen gelten sie als ungleich). WennA.__eq__
es falsch implementiert ist (RückgabeFalse
stattNotImplemented
wenn es die andere Seite nicht erkennt), dann ist dies ausA
der Sicht "korrekt" , RückgabeTrue
(daA
es nicht gleich ist, also nicht gleich), aber es könnte sein falsch vonsomething_A_knows_nothing_about
's Perspektive, da es nie gefragt hatsomething_A_knows_nothing_about
;A() != something_A_knows_nothing_about
endetTrue
,something_A_knows_nothing_about != A()
könnte aberFalse
oder einen anderen Rückgabewert.Das Problem mit
not self == other
ist subtiler. Es wird für 99% der Klassen korrekt sein, einschließlich aller Klassen, für die
__ne__
die logische Umkehrung von ist__eq__
. Verstößtnot self == other
jedoch gegen beide oben genannten Regeln, was bedeutet, dass für Klassen, bei denen dies__ne__
nicht die logische Umkehrung ist__eq__
, die Ergebnisse erneut nicht symmetrisch sind, da einer der Operanden nie gefragt wird, ob er überhaupt implementiert werden kann__ne__
, selbst wenn der andere Operand kann nicht. Das einfachste Beispiel ist eine verrückte Klasse, dieFalse
für alle Vergleiche zurückgibt , alsoA() == Incomparable()
undA() != Incomparable()
beide zurückgebenFalse
. Bei einer korrekten Implementierung vonA.__ne__
(eine, die zurückgegeben wird,NotImplemented
wenn sie nicht weiß, wie der Vergleich durchgeführt werden soll) ist die Beziehung symmetrisch.A() != Incomparable()
undIncomparable() != A()
einigen sich auf das Ergebnis (weil im ersteren FallA.__ne__
kehrtNotImplemented
, dannIncomparable.__ne__
kehrtFalse
, während in den letzteren,Incomparable.__ne__
kehrtFalse
direkt). Aber wennA.__ne__
implementiert istreturn not self == other
,A() != Incomparable()
gibt return zurückTrue
(weilA.__eq__
return nichtNotImplemented
, dannIncomparable.__eq__
returnFalse
und kehrtA.__ne__
das in umTrue
), währendIncomparable() != A()
return zurückkehrtFalse.
Sie können ein Beispiel dafür in Aktion sehen hier .
Offensichtlich eine Klasse, die
False
für beide immer zurückkehrt__eq__
und__ne__
ein wenig seltsam ist. Aber wie bereits erwähnt,__eq__
und__ne__
müssen nicht einmal zurückkehrenTrue
/False
; Das SQLAlchemy ORM verfügt über Klassen mit Komparatoren, die ein spezielles Proxy-Objekt für die Abfrageerstellung zurückgeben, nichtTrue
/False
überhaupt nicht (sie sind "wahr", wenn sie in einem booleschen Kontext ausgewertet werden, aber sie sollten niemals in einem solchen Kontext ausgewertet werden).Durch die Überlastung Fehler
__ne__
richtig, Sie werden brechen Klassen dieser Art, wie der Code:funktioniert (vorausgesetzt, SQLAlchemy weiß, wie man überhaupt
MyClassWithBadNE
in eine SQL-Zeichenfolge einfügt; dies kann mit Typadaptern erfolgen, ohneMyClassWithBadNE
überhaupt zusammenarbeiten zu müssen) und übergibt das erwartete Proxy-Objekt anfilter
, während:wird am Ende
filter
eine Ebene übergebenFalse
, daself == other
ein Proxy-Objekt zurückgegeben wird undnot self == other
nur das wahrheitsgemäße Proxy-Objekt in konvertiert wirdFalse
. Hoffentlich wirdfilter
eine Ausnahme ausgelöst, wenn ungültige Argumente wie behandelt werdenFalse
. Während ich sicher , dass viele bin wird argumentieren , dassMyTable.fieldname
sollte auf der linken Seite des Vergleichs konsequent sein, bleibt die Tatsache , dass es keinen programmatischer Grund , dies im allgemeinen Fall zu erzwingen, und eine korrekte allgemeine__ne__
Wille Arbeit so oder so, währendreturn not self == other
nur Werke in einer Anordnung.quelle
Kurze Antwort: Ja (aber lesen Sie die Dokumentation, um es richtig zu machen)
Die Implementierung der
__ne__
Methode durch ShadowRanger ist die richtige (und es ist zufällig die Standardimplementierung der__ne__
Methode seit Python 3.4):Warum? Weil es eine wichtige mathematische Eigenschaft behält, die Symmetrie des
!=
Operators. Dieser Operator ist binär, daher sollte sein Ergebnis vom dynamischen Typ beider Operanden abhängen , nicht nur von einem. Dies wird über Doppelversand für Programmiersprachen implementiert, die Mehrfachversand ermöglichen (wie z. B. Julia ). In Python, das nur den Einzelversand zulässt, wird der Doppelversand für numerische Methoden und umfangreiche Vergleichsmethoden simuliert , indem der WertNotImplemented
in den Implementierungsmethoden zurückgegeben wird, die den Typ des anderen Operanden nicht unterstützen. Der Interpreter versucht dann die reflektierte Methode des anderen Operanden.Die Implementierung
not self == other
der__ne__
Methode durch Aaron Hall ist falsch, da dadurch die Symmetrie des!=
Operators aufgehoben wird. In der Tat kann es niemals zurückkehrenNotImplemented
(not NotImplemented
istFalse
) und daher kann die__ne__
Methode mit höherer Priorität niemals auf die__ne__
Methode mit niedrigerer Priorität zurückgreifen .not self == other
war früher die Standard-Python 3-Implementierung der__ne__
Methode, aber es war ein Fehler, der im Januar 2015 in Python 3.4 behoben wurde, wie ShadowRanger bemerkte (siehe Problem Nr. 21408 ).Implementierung der Vergleichsoperatoren
In der Python-Sprachreferenz für Python 3 heißt es in Kapitel III Datenmodell :
Die Übersetzung in Python-Code ergibt (mit
operator_eq
for==
,operator_ne
for!=
,operator_lt
for<
,operator_gt
for>
,operator_le
for<=
undoperator_ge
for>=
):Standardimplementierung der Vergleichsmethoden
Die Dokumentation fügt hinzu:
Die Standardimplementierung der Vergleichsmethoden (
__eq__
,__ne__
,__lt__
,__gt__
,__le__
und__ge__
) kann so gegeben sein durch :Dies ist also die korrekte Implementierung der
__ne__
Methode. Und es gibt nicht immer die Umkehrung des__eq__
Verfahrens , weil , wenn die__eq__
Methode zurückgibtNotImplemented
, seine Umkehrungnot NotImplemented
istFalse
(wiebool(NotImplemented)
istTrue
) anstelle des gewünschtenNotImplemented
.Falsche Implementierungen von
__ne__
Wie Aaron Hall oben gezeigt hat,
not self.__eq__(other)
ist dies nicht die Standardimplementierung der__ne__
Methode. Aber noch istnot self == other
. Letzteres wird im Folgenden demonstriert, indem das Verhalten der Standardimplementierung mit dem Verhalten dernot self == other
Implementierung in zwei Fällen verglichen wird:__eq__
Methode gibt zurückNotImplemented
;__eq__
Methode gibt einen anderen Wert als zurückNotImplemented
.Standardimplementierung
Mal sehen, was passiert, wenn die
A.__ne__
Methode die Standardimplementierung verwendet und dieA.__eq__
Methode zurückgibtNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
AnrufeA.__eq__
.A.__eq__
kehrt zurückNotImplemented
.!=
AnrufeB.__ne__
.B.__ne__
kehrt zurück"B.__ne__"
.Dies zeigt, dass bei der
A.__eq__
RückgabeNotImplemented
derA.__ne__
Methode auf dieB.__ne__
Methode zurückgegriffen wird.Nun wollen wir sehen, was passiert, wenn die
A.__ne__
Methode die Standardimplementierung verwendet und dieA.__eq__
Methode einen anderen Wert zurückgibt alsNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
AnrufeA.__eq__
.A.__eq__
kehrt zurückTrue
.!=
kehrt zurücknot True
, das heißtFalse
.Dies zeigt, dass in diesem Fall die
A.__ne__
Methode die Umkehrung der Methode zurückgibtA.__eq__
. Somit__ne__
verhält sich die Methode wie in der Dokumentation angegeben.Das Überschreiben der Standardimplementierung der
A.__ne__
Methode mit der oben angegebenen korrekten Implementierung führt zu denselben Ergebnissen.not self == other
ImplementierungMal sehen, was passiert, wenn die Standardimplementierung der
A.__ne__
Methode mit dernot self == other
Implementierung überschrieben wird und dieA.__eq__
Methode zurückgibtNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
Anrufe==
.==
AnrufeA.__eq__
.A.__eq__
kehrt zurückNotImplemented
.==
AnrufeB.__eq__
.B.__eq__
kehrt zurückNotImplemented
.==
kehrt zurückA() is B()
, das heißtFalse
.A.__ne__
kehrt zurücknot False
, das heißtTrue
.Die Standardimplementierung der zurückgegebenen
__ne__
Methode"B.__ne__"
nichtTrue
.Nun wollen wir sehen, was passiert, wenn die Standardimplementierung der
A.__ne__
Methode mit dernot self == other
Implementierung überschrieben wird und dieA.__eq__
Methode einen anderen Wert zurückgibt alsNotImplemented
:!=
AnrufeA.__ne__
.A.__ne__
Anrufe==
.==
AnrufeA.__eq__
.A.__eq__
kehrt zurückTrue
.A.__ne__
kehrt zurücknot True
, das heißtFalse
.Die Standardimplementierung der
__ne__
Methode wurde auchFalse
in diesem Fall zurückgegeben.Da diese Implementierung das Verhalten der Standardimplementierung der
__ne__
Methode bei der__eq__
Rückgabe der Methode nicht repliziertNotImplemented
, ist sie falsch.quelle
__ne__
Methode nicht repliziert , wenn die__eq__
Methode NotImplemented zurückgibt, ist sie falsch." -A
definiert bedingungslose Gleichheit. Also ,A() == B()
. AlsoA() != B()
sollte es falsch sein , und das ist es auch . Die angegebenen Beispiele sind pathologisch (dh__ne__
sollten keine Zeichenfolge zurückgeben und__eq__
sollten nicht davon abhängen__ne__
- sondern__ne__
sollten davon abhängen__eq__
, was die Standarderwartung in Python 3 ist). Ich bin immer noch -1 bei dieser Antwort, bis Sie meine Meinung ändern können.NotImplemented
wenn er den Betrieb für ein gegebenes Paar von Argumenten nicht implementiert Vereinbarungs.False
UndTrue
ist für einen erfolgreichen Vergleich zurückgegeben. Allerdings sind diese Methoden einen Wert zurückgeben Wenn der Vergleichsoperator in einem booleschen Kontext verwendet wird (z. B. unter der Bedingung einer if-Anweisung), ruft Pythonbool()
den Wert auf, um festzustellen, ob das Ergebnis wahr oder falsch ist. "__ne__
tötet eine wichtige mathematische Eigenschaft, die Symmetrie des!=
Operators. Dieser Operator ist binär, daher sollte sein Ergebnis vom dynamischen Typ beider Operanden abhängen , nicht nur von einem. Dies wird in Programmiersprachen über Doppelversand für eine Sprache, die Mehrfachversand ermöglicht, korrekt implementiert . In Python, das nur den Einzelversand zulässt, wird der Doppelversand durch Rückgabe desNotImplemented
Werts simuliert .B
, dass die Renditen eine truthy Zeichenfolge auf allen Kontrollen__ne__
, undA
dass die RenditenTrue
auf allen Kontrollen__eq__
. Dies ist ein pathologischer Widerspruch. In einem solchen Widerspruch wäre es am besten, eine Ausnahme zu machen. Ohne Kenntnis vonB
,A
ist nicht verpflichtet , zu respektierenB
‚s Umsetzung der__ne__
für die Zwecke der Symmetrie. An diesem Punkt im Beispiel ist es für mich irrelevant , wieA
Geräte eingesetzt werden__ne__
. Bitte finden Sie einen praktischen, nicht pathologischen Fall, um Ihren Standpunkt zu verdeutlichen. Ich habe meine Antwort aktualisiert, um Sie anzusprechen.__ne__
in typischen Anwendungsfällen funktioniert, es nicht richtig macht. Boeing 737 MAX Flugzeuge flogen 500.000 Flüge vor den Abstürzen…Wenn alle
__eq__
,__ne__
,__lt__
,__ge__
,__le__
, und__gt__
ein Sinn für die Klasse, dann implementieren gerade__cmp__
statt. Ansonsten mach, was du tust, wegen dem, was Daniel DiPaolo gesagt hat (während ich es getestet habe, anstatt es nachzuschlagen;))quelle
__cmp__()
spezielle Methode wird in Python 3.x nicht mehr unterstützt, daher sollten Sie sich an die Verwendung der umfangreichen Vergleichsoperatoren gewöhnen.