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?
hash
-Werte haben. id
-Werte haben. obj1 is obj2
aufgerufen wird, werden die id
Werte beider Objekte verglichen, nicht ihre hash
Werte. 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.
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).
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>
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.
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).
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.