Geschichte der Frage:
In Python erfolgt der Vergleich von Objekten nach Werten über den Operator '==', der im Hintergrund die Methode eq aufruft. Das Standardverhalten dieser Methode wird von object geerbt und vergleicht die Identität der Objekte (für die meisten Klassen).
Problem:
Wenn wir wollen, dass Instanzen benutzerdefinierter Klassen sinnvoll verglichen werden (z.B. sollten zwei verschiedene Objekte Person mit identischem Datensatz als gleich betrachtet werden), reicht das Standardverhalten nicht aus — es ist erforderlich, ausdrücklich zu definieren, wie der Vergleich erfolgt.
Lösung:
Um das Verhalten von '==' zu ändern, muss die Methode eq in der eigenen Klasse überschrieben werden. Wenn die Klasse hashierbar sein soll, muss auch hash überschrieben werden.
Codebeispiel:
class Person: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): if not isinstance(other, Person): return NotImplemented return self.name == other.name and self.age == other.age p1 = Person("Ann", 25) p2 = Person("Ann", 25) print(p1 == p2) # True
Wichtige Merkmale:
Ist der Vergleich '==' immer symmetrisch für Objekte unterschiedlicher Typen?
Nicht unbedingt — wenn das erste Objekt NotImplemented zurückgibt, wird der umgekehrte Vergleich aufgerufen. Andernfalls könnte es zu Asymmetrie kommen.
class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False
Wenn eq nicht implementiert wird, wie werden Objekte einer benutzerdefinierten Klasse verglichen?
Es wird die ID (Identität im Speicher, nicht die Werte der Attribute) verglichen.
class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False
Kann eq ohne hash für Objekte, die als Schlüssel in einem Wörterbuch verwendet werden sollen, definiert werden?
Nein. Wenn eq geändert wird, sollte auch hash definiert werden, andernfalls wird das Objekt nicht hashierbar (TypeError bei Verwendung als Schlüssel).
class Foo: def __eq__(self, other): return True # hash wird von object geerbt, aber das Verhalten wird unvorhersehbar sein # Es ist besser, __hash__ explizit zu definieren
Negativer Fall
Bei der Gestaltung der Klasse ValueObject wurde im Team nicht berücksichtigt, dass nur eq implementiert wurde, nicht hash. Bei dem Versuch, das Objekt als Schlüssel in einem Wörterbuch oder Element in einer Menge zu verwenden, trat eine Ausnahme vom Typ TypeError auf.
Vorteile:
Schnelle Einführung benutzerdefinierter Vergleiche.
Nachteile:
Unmöglichkeit, Objekte in Mengen und Wörterbüchern zu verwenden, Schwierigkeiten bei der Fehlersuche.
Positiver Fall
In einem anderen Projekt haben die Entwickler beide Methoden — eq und hash — explizit implementiert und strengen Regeln gefolgt: Wenn zwei Objekte nach eq gleich sind, stimmen ihre Hashwerte überein.
Vorteile:
Korrekte Funktionsweise von Hash-Strukturen, konsistentes Verhalten, einfache Wartung.
Nachteile:
Verlust an Flexibilität: Gleichwertige Objekte sind in Hash-Containern nicht unterscheidbar.