Typen, die `__eq__` definieren sind unhashable?
-
05-07-2019 - |
Frage
Ich hatte einen seltsamen Fehler, wenn ein Feature den Python 3.1 Gabel meines Programms zu portieren. Ich verengte an die folgende Hypothese nach unten:
Im Gegensatz zu Python 2.x in Python 3.x, wenn ein Objekt eine __eq__
Methode hat es automatisch unhashable ist.
Ist das wahr?
Hier ist, was in Python geschieht 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 Folgefrage ist, wie löse ich mein persönliches Problem? Ich habe ein Objekt, das eine ChangeTracker
WeakKeyDictionary
speichert, die auf mehrere Objekte Punkte, für jeden den Wert ihrer Beize-Dump zu einem bestimmten Zeitpunkt in der Vergangenheit geben. Jedes Mal, wenn ein vorhandenes Objekt freigegeben wird, wird die Änderung Tracker sagt, ob seine neue Beize zu seinem alten identisch ist daher zu sagen, ob das Objekt in der Zwischenzeit verändert hat. Das Problem ist, jetzt kann ich nicht einmal prüfen, ob das angegebene Objekt in der Bibliothek ist, weil es macht es eine Ausnahme über das Objekt erhöht unhashable zu sein. (Denn es hat eine __eq__
Methode.) Wie kann ich dieses Problem umgehen?
Lösung
Ja, wenn Sie __eq__
definieren, der Standard-__hash__
(nämlich im Speicher die Adresse des Objekts Hashing) geht weg. Dies ist wichtig, weil Hashing mit Gleichheit konsistent sein muss. Gleich Objekte müssen die gleiche Hash
Die Lösung ist einfach:. Nur __hash__
definieren zusammen mit __eq__
definieren
Andere Tipps
Dieser Absatz von http://docs.python.org/3.1 /reference/datamodel.html#object. Hash
Wenn eine Klasse, die
__eq__()
überschreibt muss die Umsetzung behalten__hash__()
von einer übergeordneten Klasse, der Dolmetscher muss dies gesagt werden, explizit durch__hash__ = <ParentClass>.__hash__
Einstellung. Ansonsten der Vererbung von__hash__()
wird blockiert, wie wenn__hash__
gewesen explizit auf Keine.
Überprüfen Sie die Python 3 Handbuch auf object.__hash__
:
Wenn eine Klasse definiert keine
__eq__()
Methode es keine__hash__()
Operation definieren sollte entweder; , wenn es__eq__()
definiert, aber nicht__hash__()
, seine Instanzen als Elemente in hashable Sammlungen nicht nutzbar sein werden.
Der Schwerpunkt liegt sie.
Wenn Sie faul sein wollen, es klingt wie Sie nur __hash__(self)
definieren id(self)
zurückzukehren:
Benutzerdefinierte Klassen haben
__eq__()
und__hash__()
Methoden standardmäßig; mit ihnen, zu vergleichen, alle Objekte ungleich (außer mit sich selbst) undx.__hash__()
kehrtid(x)
.
Ich bin kein Python-Experte, aber wäre es nicht sinnvoll, dass, wenn Sie eine eq-Methode zu definieren, können Sie auch als auch ein Hash-Verfahren definieren müssen (die den Hash-Wert für ein Objekt berechnet) Andernfalls der Hashing-Mechanismus würde nicht wissen, ob es das gleiche Objekt treffen, oder ein anderes Objekt nur mit dem gleichen Hash-Wert. Eigentlich ist es umgekehrt, es würde wahrscheinlich verschiedene Hash-Werte für Objekte als gleich von Ihrer __eq__
Methode am Ende der Berechnung.
Ich habe keine Ahnung, was die Hash-Funktion, obwohl genannt wird, __hash__
vielleicht? :)