Elegante Möglichkeiten, Äquivalenz ("Gleichheit") in Python-Klassen zu unterstützen
Beim schreiben von benutzerdefinierten Klassen ist es oft wichtig, dass die Gleichwertigkeit durch die ==
und !=
Betreiber. In Python, möglich wird dies durch die Umsetzung der __eq__
und __ne__
spezielle Methoden, beziehungsweise. Der einfachste Weg, die ich gefunden habe, um dies zu tun, ist die folgende Methode:
class Foo:
def __init__(self, item):
self.item = item
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
else:
return False
def __ne__(self, other):
return not self.__eq__(other)
Kennen Sie mehr elegante Art, dies zu tun? Kennen Sie eine insbesondere Nachteile bei der Verwendung der oben genannten Methode zu vergleichen __dict__
s?
Hinweis: Ein wenig Klarstellung-wenn __eq__
und __ne__
sind nicht definiert, Sie finden dieses Verhalten:
>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
False
Dass a == b
ausgewertet False
weil es wirklich läuft a is b
eine Prüfung der Identität (D. H., "Ist a
auf das gleiche Objekt wie b
?").
Wenn __eq__
und __ne__
definiert sind, finden Sie dieses Verhalten (das ist die eine, die wir suchen):
>>> a = Foo(1)
>>> b = Foo(1)
>>> a is b
False
>>> a == b
True
InformationsquelleAutor der Frage |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Betrachten Sie dieses einfache problem:
So, Python standardmäßig verwendet die Objekt-IDS für Vergleichsoperationen:
Überschreiben der
__eq__
Funktion scheint das problem zu lösen:In Python 2immer daran denken, überschreiben Sie die
__ne__
- Funktion als auch, wie die Dokumentation Staaten:In Python 3ist dies nicht mehr notwendig, da die Dokumentation Staaten:
Aber, dass nicht alle unsere Probleme lösen. Fügen wir eine Unterklasse:
Hinweis: Python 2 gibt es zwei Arten von Klassen:
classic-Stil (oder alten Stil) - Klassen, die nicht Erben von
object
und deklariert werden, wieclass A:
class A():
oderclass A(B):
woB
ist ein Klassiker-Stil-Klasse;neuen Stil Klassen, die Erben von
object
und deklariert werden, wieclass A(object)
oderclass A(B):
woB
ist ein new-style Klasse. Python 3 hat nur new-style-Klassen deklariert sind, alsclass A:
class A(object):
oderclass A(B):
.Für classic-style-Klassen, ein Vergleich Betrieb immer ruft die Methode des ersten Operanden, während es für die new-style-Klassen, es ruft immer die Methode der Unterklasse Operanden, unabhängig von der Reihenfolge der Operanden.
Also hier, wenn
Number
ist ein Klassiker-Stil-Klasse:n1 == n3
Anrufen1.__eq__
;n3 == n1
Anrufen3.__eq__
;n1 != n3
Anrufen1.__ne__
;n3 != n1
Anrufen3.__ne__
.Und wenn
Number
ist eine new-style class:n1 == n3
undn3 == n1
nennenn3.__eq__
;n1 != n3
undn3 != n1
nennenn3.__ne__
.To fix the non-commutativity Problem der
==
und!=
Betreiber für Python 2 classic-style-Klassen, die__eq__
und__ne__
Methoden sollte die Rückkehr derNotImplemented
Wert, wenn ein operand-Typ wird nicht unterstützt. Die Dokumentation definiert dieNotImplemented
Wert:In diesem Fall wird der Betreiber die Delegierten der Vergleichsvorgang auf der reflektierte Methode der anderen Operanden. Die Dokumentation definiert, reflektiert Methoden:
Das Ergebnis sieht wie folgt aus:
Rücksendung der
NotImplemented
Wert stattFalse
ist, das richtige zu tun, auch für die new-style-Klassen, wenn commutativity der==
und!=
Betreiber erwünscht ist, wenn die Operanden von nicht verwandten Arten (keine Vererbung).Sind wir schon da? Nicht ganz. Wie viele eindeutige zahlen haben wir?
Sets verwenden Sie die hashes der Objekte, und standardmäßig Python gibt den hash-Wert der id des Objekts. Lassen Sie uns versuchen, um es zu überschreiben:
Das Endergebnis sieht wie folgt aus (ich habe einige Behauptungen am Ende für die Validierung):
InformationsquelleAutor der Antwort
Müssen Sie vorsichtig sein mit Vererbung:
Check-Typen genauer, wie diese:
Außer, dass dein Ansatz funktionieren, das ist, was die speziellen Methoden gibt es für.
InformationsquelleAutor der Antwort
Die Art und Weise, die Sie beschreiben, ist die Art, wie ich es immer getan haben. Da ist es völlig generisch ist, können Sie immer die Pause, die Funktionalität in eine mixin-Klasse und erbt es Klassen, in denen Sie möchten, dass die Funktionalität.
InformationsquelleAutor der Antwort
Nicht eine direkte Antwort, schien aber relevant genug zu sein, wendete auf als es spart ein bisschen verbose Langeweile bei Gelegenheit. Gerade geschnitten, aus der docs...
functools.total_ordering(cls)
Gegeben eine Klasse definieren Sie einen oder mehrere reiche Vergleich Bestell-Methoden, die diese Klasse decorator versorgt den rest. Dies vereinfacht den Aufwand bei der Angabe aller möglichen reiche Vergleichsoperationen:
Muss die Klasse definieren, lt(), le(), gt(), oder ge(). Darüber hinaus sollte die Klasse Versorgung ein eq () - Methode.
Neu in version 2.7
InformationsquelleAutor der Antwort
Du nicht überschreiben, sowohl
__eq__
und__ne__
können Sie überschreiben nur__cmp__
aber dadurch wird eine Wirkung auf das Ergebnis von ==, !==, < , > und so weiter.is
tests für Objekt-Identität. Dies bedeutet eineis
bTrue
in dem Fall, wenn a und b beide halten den Verweis auf dasselbe Objekt. In python geben, die Sie immer halten eine Referenz auf ein Objekt in einer variable nicht das eigentliche Objekt, also im wesentlichen für a ist b, wahr zu sein die Objekte in Ihnen sollte sich in der gleichen Position im Speicher. Wie und vor allem warum würden Sie gehen über das überschreiben dieses Verhalten?Edit: ich wusste nicht
__cmp__
entfernen von python 3 so vermeiden Sie es.InformationsquelleAutor der Antwort
Aus dieser Antwort: https://stackoverflow.com/a/30676267/541136 habe ich gezeigt, dass, während es richtig zu definieren
__ne__
im Hinblick auf__eq__
- stattsollten Sie verwenden:
InformationsquelleAutor der Antwort
Ich denke, dass die beiden Begriffe, die du suchst Gleichheit (==) und Identität (ist). Zum Beispiel:
InformationsquelleAutor der Antwort
'Ist' test-test für die Identität mit dem builtin 'id ()" - Funktion, die im wesentlichen liefert die Speicheradresse des Objekts und kann daher nicht overloadable.
Aber in dem Fall der Prüfung der Gleichheit der a-Klasse werden Sie wahrscheinlich wollen, um ein bisschen mehr strenge über Ihre tests, und vergleichen Sie nur die Daten, die Attribute in der Klasse:
Dieser code wird nur dann vergleichen Sie nicht die Funktion Daten-member der Klasse sowie das überspringen etwas privates, das ist in der Regel, was Sie wollen. Im Fall von Plain Old Python-Objekte-ich habe eine Basis-Klasse implementiert die __init__, __str__, __repr__ und __eq__, so dass mein POPO Objekte tragen nicht die Last aller, die extra (und in den meisten Fällen identisch) Logik.
InformationsquelleAutor der Antwort