Gibt es einen Unterschied zwischen ==
y is
in Python?
Ja, sie haben einen sehr wichtigen Unterschied.
==
: Prüfung auf Gleichheit - die Semantik besagt, dass äquivalente Objekte (die nicht unbedingt dasselbe Objekt sind) als gleich getestet werden. Da die Dokumentation sagt :
Die Operatoren <, >, ==, >=, <= und != vergleichen die Werte von zwei Objekten.
is
Identitätsprüfung - die Semantik ist, dass das Objekt (wie im Speicher gehalten) ist das Objekt. Auch hier gilt, dass die Dokumentation sagt :
Die Betreiber is
y is not
Test auf Objektidentität: x is y
ist wahr wenn und nur wenn x
y y
sind das gleiche Objekt. Die Objektidentität wird mit Hilfe der id()
Funktion. x is not y
ergibt den Kehrwert Wahrheitswert.
Die Identitätsprüfung ist also dasselbe wie die Prüfung der Gleichheit der IDs der Objekte. Das heißt,
a is b
ist dasselbe wie:
id(a) == id(b)
wobei id
ist die eingebaute Funktion, die eine Ganzzahl zurückgibt, die "unter gleichzeitig existierenden Objekten garantiert eindeutig ist" (siehe help(id)
) und wo a
y b
sind beliebige Objekte.
Andere Verwendungszwecke
Sie sollten diese Vergleiche aufgrund ihrer Semantik verwenden. Verwenden Sie is
zur Überprüfung der Identität und ==
um die Gleichheit zu prüfen.
Im Allgemeinen verwenden wir also is
um die Identität zu überprüfen. Dies ist in der Regel nützlich, wenn wir nach einem Objekt suchen, das nur einmal im Speicher vorhanden sein sollte, was in der Dokumentation als "Singleton" bezeichnet wird.
Anwendungsfälle für is
umfassen:
None
- Enum-Werte (bei Verwendung von Enums aus dem Enum-Modul)
- in der Regel Module
- normalerweise Klassenobjekte, die sich aus Klassendefinitionen ergeben
- normalerweise Funktionsobjekte, die sich aus Funktionsdefinitionen ergeben
- alles andere, das nur einmal im Speicher vorhanden sein sollte (im Allgemeinen alle Singletons)
- ein bestimmtes Objekt, das Sie nach Identität suchen
Übliche Anwendungsfälle für ==
umfassen:
- Zahlen, einschließlich ganzer Zahlen
- Zeichenketten
- Listen
- setzt
- Wörterbücher
- benutzerdefinierte veränderbare Objekte
- andere eingebaute unveränderliche Objekte, in den meisten Fällen
Der allgemeine Anwendungsfall, wiederum für ==
ist, dass das gewünschte Objekt möglicherweise nicht das dieselbe Objekt, stattdessen kann es sich um ein gleichwertig eine
PEP 8 Richtungen
PEP 8, der offizielle Python-Style-Guide für die Standardbibliothek, erwähnt ebenfalls zwei Anwendungsfälle für is
:
Vergleiche mit Singletons wie None
sollte immer mit is
oder is not
, niemals die Gleichheitsoperatoren.
Hüten Sie sich auch davor, zu schreiben if x
wenn Sie wirklich meinen if x is not None
-- z.B. beim Testen, ob eine Variable oder ein Argument, das standardmäßig auf None
auf einen anderen Wert gesetzt wurde. Der andere Wert könnte einen Typ haben (wie wie ein Container), der in einem booleschen Kontext falsch sein könnte!
Von der Identität auf die Gleichheit schließen
Wenn is
wahr ist, kann Gleichheit in der Regel abgeleitet werden - wenn ein Objekt sich selbst ist, dann sollte es logischerweise als gleichwertig mit sich selbst getestet werden.
In den meisten Fällen ist diese Logik richtig, aber sie hängt von der Implementierung der __eq__
besondere Methode. Da die docs sagen,
Das Standardverhalten für den Gleichheitsvergleich ( ==
y !=
) basiert auf der Identität der Objekte. Daher führt der Gleichheitsvergleich von Instanzen mit der gleichen Identität ergibt Gleichheit, und der Gleichheitsvergleich von Instanzen mit unterschiedlichen Identitäten führt zu Ungleichheit. A Motivation für dieses Standardverhalten ist der Wunsch, dass alle Objekte reflexiv sein sollten (d.h. x ist y impliziert x == y).
und empfiehlt im Interesse der Kohärenz:
Der Gleichheitsvergleich sollte reflexiv sein. Mit anderen Worten, identische Objekte sollten gleich verglichen werden:
x is y
impliziert x == y
Wir sehen, dass dies das Standardverhalten für benutzerdefinierte Objekte ist:
>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)
Der umgekehrte Fall trifft in der Regel auch zu: Wenn etwas nicht gleich ist, kann man daraus schließen, dass es sich nicht um dasselbe Objekt handelt.
Da Gleichheitstests angepasst werden können, gilt diese Schlussfolgerung nicht immer für alle Typen.
Eine Ausnahme
Eine bemerkenswerte Ausnahme ist nan
- Es wird immer als ungleich sich selbst getestet:
>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan # !!!!!
False
Die Prüfung auf Identität kann viel schneller sein als die Prüfung auf Gleichheit (die eine rekursive Prüfung der Mitglieder erfordern könnte).
Sie kann jedoch nicht als Ersatz für die Gleichheit dienen, wenn mehr als ein Objekt als gleichwertig angesehen wird.
Beachten Sie, dass beim Vergleich der Gleichheit von Listen und Tupeln davon ausgegangen wird, dass die Identität der Objekte gleich ist (da dies eine schnelle Prüfung ist). Dies kann zu Widersprüchen führen, wenn die Logik inkonsistent ist - wie es bei nan
:
>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True
Ein abschreckendes Beispiel:
Die Frage ist der Versuch, die is
um ganze Zahlen zu vergleichen. Sie sollten nicht davon ausgehen, dass eine Instanz einer Ganzzahl dieselbe Instanz ist wie eine, die durch einen anderen Verweis erhalten wurde. Diese Geschichte erklärt, warum.
Ein Kommentator hatte Code, der sich auf die Tatsache verließ, dass kleine ganze Zahlen (-5 bis 256 einschließlich) in Python Singletons sind, anstatt auf Gleichheit zu prüfen.
Wow, das kann zu einigen heimtückischen Fehlern führen. Ich hatte einen Code, der überprüfte, ob a gleich b ist, was wie gewünscht funktionierte, weil a und b typischerweise kleine Zahlen sind. Der Fehler trat erst heute auf, nach sechs Monaten in der Produktion, weil a und b schließlich groß genug waren, um nicht zwischengespeichert zu werden. - gwg
In der Entwicklung hat es funktioniert. Möglicherweise hat es einige Untests bestanden.
Und es funktionierte in der Produktion - bis der Code nach einer Ganzzahl größer als 256 suchte, woraufhin er in der Produktion fehlschlug.
Dies ist ein Produktionsfehler, der bei der Codeüberprüfung oder möglicherweise mit einem Style-Checker hätte entdeckt werden können.
Ich möchte betonen: nicht verwenden is
um ganze Zahlen zu vergleichen.