Was bedeutet "Hashable" in Python?


193

Ich habe versucht, im Internet zu suchen, konnte aber die Bedeutung von Hashable nicht finden.

Wenn sie sagen, Objekte sind hashableoder hashable objectswas bedeutet das?


1
Siehe die Dokumentation zu Hashable und der __hash__()Methode .
26sәɹoɈ

5
das sucht nach hasable Objekten oder etwas, aber keiner der Links erklärt, was hashable tatsächlich bedeutet
user1755071

Antworten:


181

Aus dem Python-Glossar :

Ein Objekt ist hashbar, wenn es einen Hashwert hat, der sich während seiner Lebensdauer nie ändert (es benötigt eine __hash__()Methode) und mit anderen Objekten verglichen werden kann (es benötigt eine __eq__()oder __cmp__()Methode). Hashbare Objekte, die gleich sind, müssen denselben Hashwert haben.

Durch die Hashability kann ein Objekt als Wörterbuchschlüssel und als festgelegtes Element verwendet werden, da diese Datenstrukturen den Hashwert intern verwenden.

Alle unveränderlichen integrierten Objekte von Python sind hashbar, während keine veränderlichen Container (wie Listen oder Wörterbücher) vorhanden sind. Objekte, die Instanzen von benutzerdefinierten Klassen sind, können standardmäßig gehasht werden. Sie alle vergleichen sich ungleich und ihr Hash-Wert ist ihr id().


2
Wenn es hash valuejetzt hat, was ist Hash-Wert.
Können

2
@ user55711: Hier ist der Hash-Wert das Ergebnis eines Aufrufs __hash__(). Allgemeiner, siehe en.wikipedia.org/wiki/Hash_function
NPE

16
@TorstenBronger: Weil zwei ungleiche Objekte denselben Wert haben können. Mit anderen Worten, Hashing ist verlustbehaftet.
NPE

1
In Python-2.7.12 ist das Ergebnis von id(object)16x das Ergebnis von object.__hash__(). Daher ist der Glossarauszug für diese Version falsch - der Hash-Wert ist es nicht id(), aber er wird daraus abgeleitet (wie in den aktualisierten Dokumenten für Python 2.7.12 angegeben).
DavidA

2
Ich weiß, dass dies ein alter Beitrag ist, aber es ist erwähnenswert, dass der hier kopierte Glossareintrag nicht ganz korrekt ist. Sie können ein veränderbares Objekt (wie eine Liste) in ein Tupel einfügen. Das Tupel ist immer noch unveränderlich, aber Sie können die darin enthaltene Liste ändern, sodass es nicht hashbar ist. Versuchen hash((1, [2, 3]))Sie es in Aktion zu sehen. Ich habe eine Anfrage zur Korrektur des Glossareintrags für Hashable veröffentlicht.
John Riehl

102

Alle Antworten hier haben eine gute funktionierende Erklärung für hashbare Objekte in Python, aber ich glaube, man muss zuerst den Begriff Hashing verstehen.

Hashing ist ein Konzept in der Informatik, mit dem hochleistungsfähige Pseudo-Direktzugriffsdatenstrukturen erstellt werden, in denen große Datenmengen gespeichert und schnell abgerufen werden sollen.

Wenn Sie beispielsweise 10.000 Telefonnummern haben und diese in einem Array speichern möchten (dies ist eine sequentielle Datenstruktur, die Daten an zusammenhängenden Speicherorten speichert und wahlfreien Zugriff bietet), aber möglicherweise nicht über die erforderliche Anzahl zusammenhängender Telefonnummern verfügen Speicherplätze.

Sie können stattdessen ein Array der Größe 100 verwenden und eine Hash-Funktion verwenden, um eine Reihe von Werten denselben Indizes zuzuordnen. Diese Werte können in einer verknüpften Liste gespeichert werden. Dies bietet eine ähnliche Leistung wie ein Array.

Eine Hash-Funktion kann nun so einfach sein, dass Sie die Zahl durch die Größe des Arrays teilen und den Rest als Index verwenden.

Weitere Informationen finden Sie unter https://en.wikipedia.org/wiki/Hash_function

Hier ist eine weitere gute Referenz: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
Das ist eine interessante Perspektive auf Hashing. Ich habe es nicht so gesehen.
Yuvgin

@ yuvgin-Hash-Tabellen werden häufig verwendet, um Sparse-Arrays zu implementieren (dh das hier angegebene Beispiel).
Eli Korvigo

@EliKorvigo Ich stelle mir reguläre Arrays gerne als einfach hochoptimierte Versionen einer Hash-Tabelle vor.
Mark Ransom

1
Können Sie einen einfachen Code für das Telefonnummern-Array-Szenario erstellen, um das Konzept des Hashings zu verdeutlichen?
Istiaque Ahmed

18

Alles, was nicht veränderlich ist (veränderbare Mittel, die sich wahrscheinlich ändern), kann gehasht werden. Neben der Hash-Funktion, nach der gesucht werden muss, wenn eine Klasse sie hat, z. dir(tuple)und auf der Suche nach der __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änderlichen Typen:

list, dict, set, bytearray, user-defined classes

Ich habe kürzlich herausgefunden, dass das Ellipsisauch ein unveränderlicher Typ ist und als Schlüssel für a verwendet werden kann dict.
Gábor Fekete

Es können auch benutzerdefinierte Klassen verwendet werden, jedoch nur deren Namen, keine Instanzen. ZB:hash(MyClass)
Gábor Fekete

1
@ GáborFekete-Instanzen von benutzerdefinierten Klassen können gehasht werden, wenn ihre Klassen __hash__und implementieren __eq__. Darüber hinaus implementieren alle benutzerdefinierten Klassen diese Methoden (und sind daher hashbar), da sie die Methoden von object(der universellen Basisklasse) erben .
Eli Korvigo

6

Nach meinem Verständnis wird nach dem Python-Glossar beim Erstellen einer Instanz von Objekten, die hashbar sind, ein unveränderlicher Wert auch anhand der Mitglieder oder Werte der Instanz berechnet. Zum Beispiel könnte dieser Wert dann als Schlüssel in einem Diktat wie folgt 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(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

Wir können feststellen, dass der Hash-Wert von tuple_a und tuple_c gleich ist, da sie dieselben Mitglieder haben. Wenn wir tuple_a als Schlüssel in dict_a verwenden, können wir feststellen, dass der Wert für dict_a [tuple_c] der gleiche ist, was bedeutet, dass sie, wenn sie als Schlüssel in einem Dikt verwendet werden, denselben Wert zurückgeben, weil die Hashwerte sind das Gleiche. Für Objekte, die nicht hashbar sind, ist der Methoden- Hash als Keine definiert:

>>> type(dict.__hash__) 
<class 'NoneType'>

Ich denke, dieser Hash-Wert wird bei der Initialisierung der Instanz berechnet, nicht auf dynamische Weise. Deshalb sind nur unveränderliche Objekte hashbar. Hoffe das hilft.


4

Lassen Sie mich Ihnen ein funktionierendes Beispiel geben, um die hashbaren Objekte in Python zu verstehen. Für dieses Beispiel nehme ich 2 Tupel. Jeder Wert in einem Tupel hat einen eindeutigen Hash-Wert, der sich während seiner Lebensdauer nie ändert. Basierend auf diesem Wert wird der Vergleich zwischen zwei Tupeln durchgeführt. Mit der ID () können wir den Hashwert eines Tupelelements ermitteln.

Vergleich zwischen 2 TupelnÄquivalenz zwischen 2 Tupeln


26
Dies wäre nützlicher als Text als ein Bild
Baxx

6
Es ist eine falsche Antwort. id () zeigt die referenzierte Adresse in einem Speicher an, es ist kein Hashwert. Um Hash zu erhalten, verwenden Sie die Funktion __hash __ (). Beispiel: t1 .__ Hash __ ()
Vlad

@ascentman Zögern Sie nicht, eine Antwort zu bearbeiten, die Sie für falsch halten. Ihre Bearbeitung wird von Experten begutachtet, und wenn sie akzeptiert wird, erhalten Sie eine kleine Punktzahl dafür.
XavierStuvw

4

In Python bedeutet dies, dass das Objekt Mitglieder von Mengen sein kann, um einen Index zurückzugeben. Das heißt, sie haben eine eindeutige Identität / ID.

Zum Beispiel in Python 3.3:

Die Datenstrukturlisten sind nicht hashbar, aber die Datenstruktur Tupel sind hashbar.


Der Hash ist nicht der gleiche wie der id, der (ungefähr) die Adresse des Objekts im Speicher ist.
Poolie

3

Hashable = kann gehasht werden.

Ok, was ist Hashing? Eine Hashing-Funktion ist eine Funktion, die ein Objekt, beispielsweise eine Zeichenfolge wie "Python", aufnimmt und einen Code mit fester Größe zurückgibt. Nehmen Sie der Einfachheit halber an, dass der Rückgabewert eine Ganzzahl ist.

Wenn ich in Python 3 Hash ('Python') ausführe, erhalte ich als Ergebnis 5952713340227947791. Verschiedene Versionen von Python können die zugrunde liegende Hash-Funktion ändern, sodass Sie wahrscheinlich einen anderen Wert erhalten. Das Wichtigste ist, dass ich, egal wie oft ich Hash ('Python') ausführe, immer das gleiche Ergebnis mit der gleichen Version von Python erhalte.

Aber Hash ('Java') gibt 1753925553814008565 zurück. Wenn sich also das Objekt, das ich hashe, ändert, ändert sich auch das Ergebnis. Wenn sich andererseits das Objekt, das ich hashe, nicht ändert, bleibt das Ergebnis gleich.

Warum ist das wichtig?

Für Python-Wörterbücher müssen die Schlüssel beispielsweise unveränderlich sein. Das heißt, Schlüssel müssen Objekte sein, die sich nicht ändern. Zeichenfolgen 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 (dh sie sind veränderlich), da Sie sie ändern können. Ebenso sind Diktate veränderlich.

Wenn wir also sagen, dass etwas hashbar ist, meinen wir, dass es unveränderlich ist. Wenn ich versuche, einen veränderlichen Typ an die Funktion hash () zu übergeben, schlägt dies fehl:

>>> 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

1
Beachten Sie, dass Python den Hashing-Algorithmus zu Beginn jedes Prozesses zufällig ausgibt. Daher erhalten Sie tatsächlich unterschiedliche Hashwerte, wenn Sie Hash ('Python') zweimal in verschiedenen Prozessen ausführen.
D Hudson

2

In Python ist jedes unveränderliche Objekt (wie eine Ganzzahl, ein Boolescher Wert, ein String oder ein Tupel) hashbar, was bedeutet, dass sich sein Wert während seiner Lebensdauer nicht ändert. Auf diese Weise kann Python einen eindeutigen Hashwert erstellen, um ihn zu identifizieren. Dieser kann von Wörterbüchern zum Verfolgen eindeutiger Schlüssel und von Sätzen zum Verfolgen eindeutiger Werte verwendet werden.

Aus diesem Grund müssen wir für Python unveränderliche Datentypen für die Schlüssel in einem Wörterbuch verwenden.


-1

Um eine Hashing-Tabelle von Grund auf neu zu erstellen, müssen alle Werte auf "Keine" gesetzt und geändert werden, sobald eine Anforderung auftritt. Hashbare Objekte beziehen sich auf die veränderbaren Datentypen (Wörterbuch, Listen usw.). Sets hingegen können nach der Zuweisung nicht erneut initialisiert werden, sodass Sets nicht hashbar sind. Die Variante von set () - frozenset () - ist hashbar.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.