Ich habe ein Python Programm, in dem zwei Variablen auf den Wert 'public'
gesetzt sind. In einem bedingten Ausdruck habe ich den Vergleich var1 is var2
, der fehlschlägt, aber wenn ich ihn in var1 == var2
ändere, wird True
zurückgegeben.
Wenn ich nun meinen Python -Interpreter öffne und den gleichen "Ist" -Vergleich durchführe, ist dies erfolgreich.
>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True
Was vermisse ich hier?
is
ist ein Identitätstest, ==
ist ein Gleichheitstest. Was in Ihrem Code passiert, wird im Interpreter folgendermaßen emuliert:
>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False
kein Wunder also, dass sie nicht gleich sind, oder?
Mit anderen Worten: is
ist die id(a) == id(b)
Andere Antworten hier sind richtig: is
wird für Identität Vergleich verwendet, während ==
für Gleichheit Vergleich verwendet wird. Da es Ihnen um Gleichheit geht (die beiden Zeichenfolgen sollten dieselben Zeichen enthalten), ist in diesem Fall der Operator is
einfach falsch, und Sie sollten stattdessen ==
verwenden.
Der Grund, warum is
interaktiv arbeitet, ist, dass (die meisten) String-Literale standardmäßig interniert sind. Aus Wikipedia:
Internierte Zeichenfolgen beschleunigen Zeichenfolgenvergleiche. Dies ist manchmal ein Leistungsengpass in Anwendungen (wie Compilern und dynamischen Programmiersprachenlaufzeiten), die stark auf Hashtabellen mit Zeichenfolgenschlüsseln angewiesen sind. Um zu überprüfen, ob zwei verschiedene Zeichenfolgen gleich sind, müssen Sie jedes Zeichen beider Zeichenfolgen untersuchen, ohne zu internieren. Dies ist aus mehreren Gründen langsam: Es ist von Natur aus O(n) in der Länge der Zeichenfolgen; In der Regel sind Lesevorgänge aus mehreren Speicherbereichen erforderlich, die einige Zeit in Anspruch nehmen. und die Lesevorgänge füllen den Prozessor-Cache, was bedeutet, dass weniger Cache für andere Anforderungen verfügbar ist. Bei internen Strings reicht ein einfacher Objektidentitätstest nach der ursprünglichen internen Operation aus. Dies wird normalerweise als Zeigergleichheitstest implementiert, normalerweise nur ein einzelner Maschinenbefehl ohne Speicherreferenz.
Wenn Sie also in Ihrem Programm zwei String-Literale (Wörter, die buchstäblich in den Quellcode Ihres Programms eingegeben werden und von Anführungszeichen umgeben sind) haben, die denselben Wert haben, werden die Strings vom Compiler Python automatisch interniert Beide werden am selben Speicherort gespeichert. (Beachten Sie, dass dies nicht immer vorkommt und die Regeln für diesen Fall ziemlich kompliziert sind. Verlassen Sie sich daher bitte nicht auf dieses Verhalten im Produktionscode!)
Da in Ihrer interaktiven Sitzung beide Zeichenfolgen tatsächlich am selben Speicherort gespeichert sind, haben sie dasselbe Identität, sodass der Operator is
wie erwartet funktioniert. Wenn Sie jedoch eine Zeichenfolge mit einer anderen Methode erstellen (auch wenn diese Zeichenfolge gena dieselben Zeichen enthält), ist die Zeichenfolge möglicherweise gleich, aber nicht dieselbe Zeichenkette - das heißt, sie hat eine andere Identität, weil sie an einer anderen Stelle im Speicher gespeichert ist.
Das Schlüsselwort is
ist ein Test für die Objektidentität, während ==
ein Wertevergleich ist.
Wenn Sie is
verwenden, ist das Ergebnis genau dann wahr, wenn das Objekt dasselbe Objekt ist. ==
ist jedoch immer dann wahr, wenn die Werte des Objekts gleich sind.
Als letztes können Sie die Funktion intern verwenden, um sicherzustellen, dass Sie einen Verweis auf dieselbe Zeichenfolge erhalten:
>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True
Wie oben erwähnt, sollten Sie wahrscheinlich nicht die Gleichheit von Zeichenfolgen bestimmen. Dies kann jedoch hilfreich sein, um zu wissen, ob Sie eine seltsame Anforderung haben, is
zu verwenden.
Beachten Sie, dass die interne Funktion von einer eingebauten Funktion in das Modul sys
für Python 3 verschoben wurde.
is
ist ein Identitätstest, ==
ist ein Gleichheitstest. Dies bedeutet, dass is
ein Weg ist, um zu überprüfen, ob zwei Dinge die gleichen Dinge sind oder nur gleichwertig.
Angenommen, Sie haben ein einfaches person
Objekt. Wenn es 'Jack' heißt und '23' Jahre alt ist, entspricht es einem anderen 23-jährigen Jack, aber es ist nicht dieselbe Person.
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)
jack1 == jack2 #True
jack1 is jack2 #False
Sie sind gleich alt, aber sie sind nicht die gleiche Person. Eine Zeichenfolge entspricht möglicherweise einer anderen, ist jedoch nicht dasselbe Objekt.
Dies ist eine Randnotiz, aber in idiomatischer Python werden Sie häufig Dinge sehen wie:
if x is None:
# some clauses
Dies ist sicher, da es ist garantiert, dass es eine Instanz des Null-Objekts gibt (d. H. Keine) .
Wenn Sie sich nicht sicher sind, was Sie tun, verwenden Sie '=='. Wenn Sie ein wenig mehr darüber wissen, können Sie 'is' für bekannte Objekte wie 'None' verwenden.
Andernfalls werden Sie sich fragen, warum die Dinge nicht funktionieren und warum dies passiert:
>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False
Ich bin mir nicht mal sicher, ob einige Dinge zwischen verschiedenen python Versionen/Implementierungen garantiert gleich bleiben.
Aufgrund meiner begrenzten Erfahrung mit Python wird is
verwendet, um zwei Objekte zu vergleichen, um festzustellen, ob es sich um dasselbe Objekt im Gegensatz zu zwei verschiedenen Objekten mit demselben Wert handelt. ==
wird verwendet, um festzustellen, ob die Werte identisch sind.
Hier ist ein gutes Beispiel:
>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True
s1
ist eine Unicode-Zeichenfolge, und s2
ist eine normale Zeichenfolge. Sie sind nicht vom gleichen Typ, haben aber den gleichen Wert.
Ich denke, das hat damit zu tun, dass, wenn der Ist-Vergleich falsch ist, zwei unterschiedliche Objekte verwendet werden. Wenn es als true ausgewertet wird, bedeutet dies, dass intern dasselbe Objekt verwendet und kein neues erstellt wird, möglicherweise, weil Sie sie innerhalb eines Bruchteils von 2 Sekunden erstellt haben und keine große Zeitlücke zwischen dem optimierten und dem optimierten Objekt besteht verwendet das gleiche Objekt.
Aus diesem Grund sollten Sie den Gleichheitsoperator ==
und nicht is
verwenden, um den Wert eines Zeichenfolgenobjekts zu vergleichen.
>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>>
In diesem Beispiel habe ich s2 erstellt, ein anderes String-Objekt, das zuvor gleich 'one' war, aber nicht dasselbe Objekt wie s
, da der Interpreter nicht dasselbe Objekt verwendet hat, wie ich es ursprünglich nicht zugewiesen habe auf "eins", wenn ich es hätte, hätte sie das gleiche Objekt gemacht.
Ich glaube, dass dies als "internierte" Zeichenfolgen bekannt ist. Python erledigt dies ebenso wie Java und C und C++, wenn in optimierten Modi kompiliert wird.
Wenn Sie zwei identische Zeichenfolgen verwenden, anstatt Speicher durch das Erstellen von zwei Zeichenfolgenobjekten zu verschwenden, verweisen alle internen Zeichenfolgen mit demselben Inhalt auf denselben Speicher.
Dies führt dazu, dass der Operator Python "is" True zurückgibt, da zwei Zeichenfolgen mit demselben Inhalt auf dasselbe Zeichenfolgenobjekt zeigen. Dies geschieht auch in Java und in C.
Dies ist jedoch nur nützlich, um Speicherplatz zu sparen. Sie können sich beim Testen der Zeichenfolgengleichheit nicht darauf verlassen, da die verschiedenen Interpreter und Compiler und JIT-Engines dies nicht immer tun können.
Ich beantworte die Frage, obwohl die Frage zu alt ist, weil oben keine Antworten den Sprachbezug zitieren
Tatsächlich überprüft der is-Operator die Identität und der ==-Operator die Gleichheit.
Aus der Sprachreferenz:
Typen beeinflussen fast alle Aspekte des Objektverhaltens. Sogar die Bedeutung der Objektidentität wird in gewisser Weise beeinflusst: Bei unveränderlichen Typen können Operationen , die neue Werte berechnen, tatsächlich einen Verweis auf ein vorhandenes Objekt mit demselben Typ und Wert zurückgeben, während dies bei veränderlichen Objekten der Fall ist nicht erlaubt. Zum Beispiel nach a = 1; b = 1, a und b können sich je nach Implementierung auf dasselbe Objekt mit dem Wert eins beziehen oder auch nicht, jedoch nach c = []; d = [], c und d beziehen sich garantiert auf zwei unterschiedliche, eindeutige, neu erstellte leere Listen. (Beachten Sie, dass c = d = [] c und d dasselbe Objekt zuweist.)
aus der obigen Aussage können wir schließen, dass die Zeichenfolgen, die ein unveränderlicher Typ sind, fehlschlagen können, wenn sie mit "is" markiert sind, und erfolgreich sein können, wenn sie mit "is" markiert sind.
Gleiches gilt für int, Tuple, die ebenfalls unveränderliche Typen sind
Die Operator-Testwertäquivalenz ==
. Der Operator is
testet die Objektidentität, Python testet, ob die beiden wirklich dasselbe Objekt sind (d. H. An derselben Adresse im Speicher leben).
>>> a = 'banana'
>>> b = 'banana'
>>> a is b
True
In diesem Beispiel hat Python nur ein Zeichenfolgenobjekt erstellt, und sowohl a
als auch b
verweisen darauf. Der Grund dafür ist, dass Python einige Zeichenfolgen intern zwischenspeichert und als Optimierung wiederverwendet. Es gibt wirklich nur eine 'Banane'-Zeichenfolge im Speicher, die von a und b gemeinsam verwendet wird. Um das normale Verhalten auszulösen, müssen Sie längere Zeichenfolgen verwenden:
>>> a = 'a longer banana'
>>> b = 'a longer banana'
>>> a == b, a is b
(True, False)
Wenn Sie zwei Listen erstellen, erhalten Sie zwei Objekte:
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> a is b
False
In diesem Fall würden wir sagen, dass die beiden Listen äquivalent sind, weil sie dieselben Elemente haben, aber nicht identisch sind, weil sie nicht dasselbe Objekt sind. Wenn zwei Objekte identisch sind, sind sie auch äquivalent, aber wenn sie äquivalent sind, sind sie nicht unbedingt identisch.
Wenn a
auf ein Objekt verweist und Sie b = a
zuweisen, verweisen beide Variablen auf dasselbe Objekt:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
is
vergleicht den Speicherort. Es wird für den Vergleich auf Objektebene verwendet.
==
vergleicht die Variablen im Programm. Es dient zur Überprüfung auf Wertebene.
is
prüft die Äquivalenz der Adressebene
==
prüft die Äquivalenz der Wertebenen
is
ist ein Identitätstest, ==
ist ein Gleichheitstest (siehe Python-Dokumentation ).
In den meisten Fällen, wenn a is b
, dann a == b
. Es gibt jedoch Ausnahmen, zum Beispiel:
>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False
Daher können Sie is
nur für Identitätstests verwenden, niemals für Gleichheitstests.