Ich hatte einen seltsamen Fehler beim Portieren einer Funktion auf den Python 3.1-Zweig meines Programms. Ich habe es auf folgende Hypothese eingegrenzt:
Im Gegensatz zu Python 2.x ist ein Objekt in Python 3.x __eq__
automatisch nicht verwertbar, wenn es über eine Methode verfügt.
Ist das wahr?
Folgendes passiert in Python 3.1:
>>> class O(object):
... def __eq__(self, other):
... return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
d = {o: 0}
TypeError: unhashable type: 'O'
Die folgende Frage lautet: Wie löse ich mein persönliches Problem? Ich habe ein Objekt, ChangeTracker
das ein Objekt speichert WeakKeyDictionary
, das auf mehrere Objekte verweist und für jedes den Wert ihres Pickle Dump zu einem bestimmten Zeitpunkt in der Vergangenheit angibt. Jedes Mal, wenn ein vorhandenes Objekt eingecheckt wird, gibt der Änderungs-Tracker an, ob die neue Gurke mit der alten identisch ist, und gibt daher an, ob sich das Objekt in der Zwischenzeit geändert hat. Das Problem ist, dass ich jetzt nicht einmal überprüfen kann, ob sich das angegebene Objekt in der Bibliothek befindet, da dadurch eine Ausnahme ausgelöst wird, dass das Objekt nicht verwertbar ist. (Weil es eine __eq__
Methode gibt.) Wie kann ich das umgehen?
quelle
__hash__
Methode angeben?Antworten:
Ja, wenn Sie definieren
__eq__
, verschwindet die Standardeinstellung__hash__
(nämlich das Hashing der Adresse des Objekts im Speicher). Dies ist wichtig, da das Hashing mit der Gleichheit übereinstimmen muss: Gleiche Objekte müssen dasselbe hashen.Die Lösung ist einfach: Definieren Sie einfach
__hash__
zusammen mit dem Definieren__eq__
.quelle
__hash__
alsreturn id(self)
.id(self)
in ist__hash__()
sicherlich falsch, es sei denn, Sie haben__eq__()
einen Vergleich nach Objektidentität definiert (was bedeutungslos erscheint). Wie wäre__eq__()
es, wenn Sie Ihre Frage mit einer echten Implementierung aktualisieren , damit wir vorschlagen können, sie zu__hash__()
ergänzen?def __eq__(): return self.__dict__ == other.__dict__
unddef __hash__(): return hash(self.__dict__.values())
Dieser Absatz von http://docs.python.org/3.1/reference/datamodel.html#object. Hash
quelle
Überprüfen Sie das Python 3-Handbuch auf
object.__hash__
:Der Schwerpunkt liegt bei mir.
Wenn Sie faul sein möchten, können Sie einfach definieren,
__hash__(self)
um zurückzukehrenid(self)
:quelle
return id(self)
Hash-Funktion fehlerhaft (gleiche Objekte müssen gleich hashen, siehe Martins Antwort). Die Hash-Funktion "Es ist mir egal" wärereturn 1
. Dies ist einfach und erfüllt alle Bedingungen (es ist nur sehr ineffizient!)Ich bin kein Python-Experte, aber wäre es nicht sinnvoll, wenn Sie eine EQ-Methode definieren, müssen Sie auch eine Hash-Methode definieren (die den Hash-Wert für ein Objekt berechnet). Andernfalls den Hashing-Mechanismus Ich würde nicht wissen, ob es dasselbe Objekt oder ein anderes Objekt mit genau demselben Hashwert trifft. Umgekehrt würde es wahrscheinlich dazu führen, dass unterschiedliche Hash-Werte für Objekte berechnet werden, die von Ihrer
__eq__
Methode als gleich angesehen werden .Ich habe keine Ahnung, wie diese Hash-Funktion
__hash__
vielleicht heißt? :) :)quelle