Achtergrond:
In Python gebeurt het vergelijken van objecten op waarde via de operator '==', die onder de motorkap de eq methode aanroept. Het standaardgedrag van deze methode wordt geërfd van object en vergelijkt de identiteit van objecten (voor de meeste klassen).
Probleem:
Wanneer we willen dat instanties van gebruikersklassen op een betekenisvolle manier worden vergeleken (bijvoorbeeld, twee verschillende Person-objecten met dezelfde set gegevens worden als gelijk beschouwd), is het standaardgedrag niet voldoende — we moeten expliciet definiëren hoe de vergelijking plaatsvindt.
Oplossing:
Om het gedrag van '==' te wijzigen, moet de eq methode in de eigen klasse worden overschreven. Als de klasse hashbaar moet zijn, moet ook hash worden overschreven.
Voorbeeldcode:
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
Belangrijke kenmerken:
Is de vergelijking '==' altijd symmetrisch voor objecten van verschillende types?
Niet noodzakelijk — als het eerste object NotImplemented retourneert, wordt de omgekeerde vergelijking aangeroepen. Anders kan er asymmetrie zijn.
class A: def __eq__(self, other): return True class B: pass print(A() == B()) # True print(B() == A()) # False
Als eq niet wordt geïmplementeerd, hoe worden objecten van dezelfde gebruikersklasse dan vergeleken?
Er zal naar de id (identiteit in geheugen, niet naar de waarden van de attributen) worden vergeleken.
class Foo: def __init__(self, x): self.x = x f1 = Foo(5) f2 = Foo(5) print(f1 == f2) # False
Kan men eq definiëren zonder hash voor objecten die als sleutels in een dictionary moeten worden gebruikt?
Nee. Als eq is gewijzigd, is het ook wenselijk om hash te definiëren, anders wordt het object niet-hashbaar (TypeError bij gebruik als sleutel).
class Foo: def __eq__(self, other): return True # hash wordt geërfd van object, maar het gedrag zal onvoorspelbaar zijn # Beter om __hash__ expliciet te definiëren
Negatieve case
Bij het ontwerpen van de klasse ValueObject in een team werd niet overwogen dat alleen eq was geïmplementeerd, maar niet hash. Bij het proberen om het object als sleutel in een dictionary of als element in een set te gebruiken, trad een TypeError-exceptie op.
Voordelen:
Snelle implementatie van gebruikersspecifieke vergelijking.
Nadelen:
Onmogelijk om objecten in sets en dictionaries te gebruiken, complexiteit bij het debuggen.
Positieve case
In een ander project implementeerden ontwikkelaars beide methoden expliciet — eq en hash, strikt volgend de regel: als twee objecten gelijk zijn in eq, moeten hun hashes overeenkomen.
Voordelen:
Correct gedrag van hash-structuren, consistente werking, eenvoudiger in onderhoud.
Nadelen:
Verlies van flexibiliteit: gelijke objecten qua waarden zijn niet te onderscheiden in hash-containers.