Unterschied zwischen hash () und id ()

9

Ich habe zwei benutzerdefinierte Objekte, sagen wir a und b .
Beide Objekte haben die gleichen hash -Werte.
Die id(a) und id(b) sind jedoch ungleich.

Außerdem

%Vor%

Kann ich aus dieser Beobachtung auf Folgendes schließen?

  • Ungleiche Objekte können die gleichen hash -Werte haben.
  • Gleiche Objekte müssen dieselben id -Werte haben.
  • Immer wenn obj1 is obj2 aufgerufen wird, werden die id Werte beider Objekte verglichen, nicht ihre hash Werte.
Kshitij Saraogi 21.12.2015, 18:57
quelle

3 Antworten

19

Beim Verständnis von id , hash und == und is sind drei Konzepte zu verstehen: Identität , Wert und < starker> Hash-Wert . Nicht alle Objekte haben alle drei.

  1. Alle Objekte haben eine Identität , auch wenn dies in einigen Fällen etwas rutschig sein kann. Die Funktion id gibt eine Zahl zurück, die der Identität eines Objekts entspricht (in cpython gibt sie die Speicheradresse des Objekts zurück, andere Interpreter können jedoch etwas anderes zurückgeben). Wenn zwei Objekte (die zur gleichen Zeit existieren) die gleiche Identität haben, sind sie eigentlich zwei Referenzen auf das gleiche Objekt. Der Operator is vergleicht Elemente nach Identität, a is b entspricht id(a) == id(b) .

    Die Identität kann ein wenig verwirrend werden, wenn Sie mit Objekten arbeiten, die irgendwo in ihrer Implementierung zwischengespeichert werden. Zum Beispiel werden die Objekte für kleine ganze Zahlen und Zeichenfolgen in cpython nicht jedes Mal neu erstellt, wenn sie verwendet werden. Stattdessen werden vorhandene Objekte jederzeit zurückgegeben, wenn sie benötigt werden. Sie sollten sich jedoch nicht darauf in Ihrem Code verlassen, da es sich um ein Implementierungsdetail von cpython handelt (andere Interpreter tun dies möglicherweise anders oder gar nicht).

  2. Alle Objekte haben auch einen Wert , obwohl dies etwas komplizierter ist. Einige Objekte haben keinen anderen Wert als ihre Identität (also kann in einigen Fällen auch eine Identität synonym sein). Der Wert kann definiert werden als was der Operator == vergleicht, also können Sie jederzeit a == b sagen, dass a und b denselben Wert haben. Containerobjekte (wie Listen) haben einen Wert, der durch ihren Inhalt definiert ist, während einige andere Arten von Objekten Werte basierend auf ihren Attributen haben. Objekte verschiedener Typen können manchmal die gleichen Werte haben wie Zahlen: 0 == 0.0 == 0j == decimal.Decimal("0") == fractions.Fraction(0) == False (yep, bool s sind Zahlen aus historischen Gründen in Python).

    Wenn eine Klasse keine __eq__ -Methode definiert (um den Operator == zu implementieren), erbt sie die Standardversion von object und ihre Instanzen werden nur anhand ihrer Identitäten verglichen. Dies ist sinnvoll, wenn ansonsten identische Instanzen wichtige semantische Unterschiede haben können. Zum Beispiel müssen zwei verschiedene Sockets, die mit demselben Port des gleichen Hosts verbunden sind, unterschiedlich behandelt werden, wenn eine HTML-Webseite abgerufen wird und die andere ein Bild erhält, das von dieser Seite verlinkt ist, so dass sie nicht denselben Wert haben / p>

  3. Zusätzlich zu einem Wert haben einige Objekte einen Hash-Wert , was bedeutet, dass sie als Wörterbuchschlüssel verwendet werden können (und in set s gespeichert werden). Die Funktion hash(a) gibt den Hashwert des Objekts a zurück, eine Zahl, die auf dem Objektwert basiert. Der Hash eines Objekts muss für die Lebensdauer des Objekts gleich bleiben. Daher ist es nur sinnvoll, dass ein Objekt hashbar ist, wenn sein Wert unveränderlich ist (entweder weil es auf der Identität des Objekts basiert oder auf dem Inhalt des Objekts basiert) Objekte, die selbst unveränderlich sind).

    Mehrere verschiedene Objekte können denselben Hash-Wert haben, obwohl durchdachte Hash-Funktionen dies so weit wie möglich vermeiden. Das Speichern von Objekten mit demselben Hash in einem Wörterbuch ist viel weniger effizient als das Speichern von Objekten mit unterschiedlichen Hashes (jede Hash-Kollision erfordert mehr Arbeit). Objekte sind standardmäßig hashbar (da ihr Standardwert ihre Identität ist, die unveränderlich ist). Wenn Sie eine __eq__ -Methode in einer benutzerdefinierten Klasse schreiben, deaktiviert Python diese Standard-Hash-Implementierung, da Ihre __eq__ -Funktion eine neue Bedeutung des Werts für ihre Instanzen definiert. Sie müssen auch eine __hash__ -Methode schreiben, wenn Sie möchten, dass Ihre Klasse weiterhin hashbar ist. Wenn Sie von einer hashbaren Klasse erben, aber nicht selbst hashbar sein möchten, können Sie __hash__ = None im Klassenrumpf setzen.

Blckknght 21.12.2015, 23:18
quelle
5
  

Ungleiche Objekte können die gleichen Hashwerte haben.

Ja, das ist wahr. Ein einfaches Beispiel ist hash(-1) == hash(-2) in CPython.

  

Gleiche Objekte müssen dieselben ID-Werte haben.

Nein, das ist im Allgemeinen falsch. Ein einfaches Gegenbeispiel von @chepner ist 5 == 5.0 , aber id(5) != id(5.0) .

  

Immer wenn obj1 is obj2 aufgerufen wird, werden die ID-Werte der beiden Objekte verglichen, nicht ihre Hash-Werte.

Ja, das ist wahr. is vergleicht die id der Objekte für die Gleichheit (in CPython ist dies die Speicheradresse des Objekts). Im Allgemeinen hat dies nichts mit dem Hash-Wert des Objekts zu tun (das Objekt muss nicht einmal hashbar sein).

    
Alex Riley 21.12.2015 19:06
quelle
1

Die Hash-Funktion wird verwendet für:

  

Vergleichen Sie Wörter im Wörterbuch während einer Wörterbuchsuche

Die ID-Funktion wird verwendet für:

  

Geben Sie die "Identität" eines Objekts zurück. Dies ist eine ganze Zahl, die garantiert für dieses Objekt während seiner Lebensdauer eindeutig und konstant ist. Zwei Objekte mit nicht überlappenden Lebensdauern können denselben id () Wert haben.

    
Ryan 21.12.2015 19:04
quelle

Tags und Links