Objekte darstellen und vergleichen · Übung
Nur stabile Werte hashen
Die Definition von __eq__ hat unbemerkt etwas geändert. Versuche, einen solchen Wert in ein Set zu legen:
class Points:
def __init__(self, amount):
self.amount = amount
def __eq__(self, other):
if not isinstance(other, Points):
return NotImplemented
return self.amount == other.amount
{Points(3)}
Python meldet TypeError: unhashable type: 'Points'.
Gleichheit und Hashing müssen zusammenpassen
Sets und Dictionarys finden ein Objekt mithilfe einer Zahl, seines Hashwerts. Gleiche Objekte müssen gleiche Hashwerte erzeugen. Vor der Definition von __eq__ beruhte sowohl die Gleichheit als auch das Hashing auf Identität. Beides passte daher zusammen.
Ein inhaltsbasiertes __eq__ zerstört diese Übereinstimmung. Python deaktiviert das Hashing, statt zuzulassen, dass ein Set gleiche Werte nicht mehr wiederfindet.
Warum lässt sich diese Klasse nach der Definition von __eq__ ohne passendes __hash__ nicht mehr als Dictionary-Schlüssel verwenden?
Hashing nur für stabile Werte wiederherstellen
Definiere __hash__ über genau den Zustand, den die Gleichheit vergleicht:
Die schreibgeschützte Property hält die unterstützte öffentliche Schnittstelle stabil. Würde sich amount nach dem Einfügen ändern, würde sein Hashwert auf eine andere Stelle zeigen. Die Suche könnte dann scheitern, obwohl das Objekt noch enthalten ist. Ein führender Unterstrich bleibt eine Konvention, keine Durchsetzung. Kapitel 8 führt einen eingefrorenen Wert ein, dessen Veränderung Python selbst ablehnt.
Bei mehreren verglichenen Attributen hashe dasselbe Tupel, das die Gleichheit vergleicht:
def __hash__(self):
return hash((self.prompt, self.answer, self.points))
Welche Klasse lässt sich sicher anhand ihrer Inhalte hashen?
Hashing ist keine Auszeichnung, die jeder Wert braucht. Ergänze es nur, wenn Sets oder Dictionary-Schlüssel zur tatsächlichen Verwendung der Klasse gehören, und nur, wenn sich der verglichene Zustand nicht ändern kann.
Die Übung macht Points und Question sicher hashbar. Die Ordnung ist eine andere Entwurfsentscheidung und folgt als Nächstes.
Aufgabe
Mache die beiden schreibgeschützten Werte sicher hashbar.
Gib Points ein __eq__ und ein passendes __hash__ über amount.
Gib Question ein __eq__ und ein passendes __hash__ über prompt, answer und points.
Beide Gleichheitsmethoden geben bei einem anderen Typ NotImplemented zurück. Ergänze noch keine Ordnungsmethoden.