Was genau bedeutet es, wenn man sagt, dass ein Objekt in Python-Code Hashable ?
Antworten
Zu viele Anzeigen?Von der Python-Glossar :
Ein Objekt ist hashfähig, wenn es einen Hashwert hat, der sich während seiner Lebensdauer nie ändert (es braucht einen
__hash__()
Methode), und kann mit anderen Objekten verglichen werden (es braucht eine__eq__()
o__cmp__()
Methode). Hashable-Objekte, die gleich verglichen werden, müssen denselben Hash-Wert haben.Die Hashfähigkeit macht ein Objekt als Wörterbuchschlüssel und als Mengenmitglied verwendbar, da diese Datenstrukturen intern den Hashwert verwenden.
Alle unveränderlichen eingebauten Objekte von Python sind hashfähig, während veränderbare Container (wie Listen oder Wörterbücher) dies nicht sind. Objekte, die Instanzen von benutzerdefinierten Klassen sind, sind standardmäßig hashfähig; sie vergleichen alle ungleich, und ihr Hash-Wert ist ihr
id()
.
Alle Antworten hier haben gute funktionierende Erklärung der hashable Objekte in Python, aber ich glaube, man muss den Begriff Hashing zuerst verstehen.
Hashing ist ein Konzept aus der Informatik, das dazu dient, leistungsstarke Datenstrukturen mit pseudozufälligem Zugriff zu schaffen, in denen große Datenmengen gespeichert und schnell abgerufen werden sollen.
Wenn Sie z. B. 10.000 Telefonnummern haben und diese in einem Array (einer sequentiellen Datenstruktur, die Daten an zusammenhängenden Speicherplätzen speichert und einen zufälligen Zugriff ermöglicht) speichern möchten, verfügen Sie möglicherweise nicht über die erforderliche Anzahl an zusammenhängenden Speicherplätzen.
Sie können also stattdessen ein Array der Größe 100 verwenden und eine Hash-Funktion einsetzen, um eine Reihe von Werten denselben Indizes zuzuordnen, und diese Werte können in einer verknüpften Liste gespeichert werden. Dies bietet eine ähnliche Leistung wie ein Array.
Eine Hash-Funktion kann so einfach sein wie die Division der Zahl durch die Größe des Arrays und die Übernahme des Rests als Index.
Für weitere Einzelheiten siehe https://en.wikipedia.org/wiki/Hash_function
Hier ist eine weitere gute Referenz: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html
Alles, was nicht veränderbar ist (veränderbar bedeutet, dass es sich ändern kann), kann gehasht werden. Neben der Hash-Funktion zu suchen, wenn eine Klasse hat es, durch zB. dir(tuple)
und die Suche nach dem __hash__
Methode, hier sind einige Beispiele
#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable
Liste der unveränderlichen Typen:
int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes
Liste der veränderbaren Typen:
list, dict, set, bytearray, user-defined classes
Nach meinem Verständnis nach Python-Glossar, wenn Sie eine Instanz von Objekten erstellen, die Hashable sind, ein unveränderlicher Wert wird auch nach den Mitgliedern oder Werte der Instanz berechnet. Dieser Wert könnte dann zum Beispiel als Schlüssel in einem Wörterbuch wie unten verwendet werden:
>>> tuple_a = (1, 2, 3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2, 3, 4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1, 2, 3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(tuple_a) == id(tuple_c) # tuple_a and tuple_c same object?
False
>>> tuple_a.__hash__() == tuple_c.__hash__() # hash of tuple_a and tuple_c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'
Wir können feststellen, dass der Hashwert von tuple_a
y tuple_c
sind identisch, da sie dieselben Mitglieder haben. Wenn wir tuple_a
als Schlüssel in dict_a
können wir feststellen, dass der Wert für dict_a[tuple_c]
gleich ist, was bedeutet, dass sie, wenn sie als Schlüssel in einem Wörterbuch verwendet werden, den gleichen Wert zurückgeben, da die Hash-Werte gleich sind. Für Objekte, die nicht hashfähig sind, kann die Methode __hash__
ist definiert als None
:
>>> type(dict.__hash__)
<class 'NoneType'>
Ich vermute, dass dieser Hash-Wert bei der Initialisierung der Instanz berechnet wird und nicht dynamisch, weshalb nur unveränderliche Objekte hashbar sind. Hoffentlich hilft das.
Hashable = verschlüsselbar.
Ok, was ist Hashing? Eine Hashing-Funktion ist eine Funktion, die ein Objekt, z. B. eine Zeichenkette wie "Python", nimmt und einen Code fester Größe zurückgibt. Der Einfachheit halber nehmen wir an, dass der Rückgabewert eine ganze Zahl ist.
Wenn ich hash('Python') in Python 3 ausführe, erhalte ich 5952713340227947791 als Ergebnis. Verschiedene Versionen von Python können die zugrunde liegende Hash-Funktion ändern, so dass Sie wahrscheinlich einen anderen Wert erhalten werden. Wichtig ist, dass ich mit der gleichen Version von Python immer das gleiche Ergebnis erhalte, egal wie oft ich hash('Python') ausführe.
Aber hash('Java') ergibt 1753925553814008565. Wenn sich also das Objekt, das ich hashe, ändert, ändert sich auch das Ergebnis. Wenn sich das Objekt, das ich hashe, nicht ändert, bleibt das Ergebnis dasselbe.
Warum ist das wichtig?
Bei Python-Wörterbüchern zum Beispiel müssen die Schlüssel unveränderlich sein. Das heißt, die Schlüssel müssen Objekte sein, die sich nicht ändern. Strings sind in Python unveränderlich, ebenso wie die anderen Grundtypen (int, float, bool). Tupel und Frozensets sind ebenfalls unveränderlich. Listen hingegen sind nicht unveränderlich (d. h. sie sind veränderbar), da sie geändert werden können. Ebenso sind Dicts veränderbar.
Wenn wir also sagen, dass etwas hashbar ist, meinen wir, dass es unveränderbar ist. Wenn ich versuche, einen veränderlichen Typ an die Hash()-Funktion zu übergeben, wird sie fehlschlagen:
>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656
- See previous answers
- Weitere Antworten anzeigen