@hendrikS: Deswegen:
Code: Alles auswählen
class Foo(object):
def __init__(self, x):
self.value = x
def __hash__(self):
return hash(self.value)
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return self.value != other.value
f = Foo('hallo')
d = {f: 'welt'}
f.value = 'tschüss'
d[f] # <-- ergibt KeyError, weil sich der Hash von f geändert hat
Bzw. mit einer Liste:
Code: Alles auswählen
class mylist(list):
def __hash__(self):
return hash(tuple(self))
l = mylist(range(10))
d = {l: 'spam'}
l.append(10)
d[l] # <-- KeyError
l2 = mylist(range(11))
d[l2] # <-- ebenfalls KeyError.
Es gibt schlichtweg keine Möglichkeit mehr, auf 'spam' zuzugreifen, sofern nicht "l" wieder in den Ausgangszustand versetzt wird.
Der Grund ist, dass 'spam' unter dem Hash von l im Dicitionary liegt, aber eigentlich unter dem Hash von l2 gespeichert sein müsste. Greift man mit dem Hash von l darauf zu, gibt es einen KeyError, weil der gespeicherte und der übergebene Schlüssel nicht wertgleich sind, greift man über l2 darauf zu, stimmt der Hash nicht.
Das dahinter liegende Problem ist, dass man bei einer Veränderung des Werts des Schlüssels den dazugehören Wert im Dictionary entsprechend seines neuen Hashs verschieben müsste. Dazu aber müsste man jede Attributveränderung des Schlüssels abfangen, was nicht vertretbar ist.