it-swarm.com.de

Warum führt der Vergleich von Zeichenfolgen mit '==' oder 'is' manchmal zu einem anderen Ergebnis?

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?

1052
jottos

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)

1427
SilentGhost

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.

522
Daniel Pryden

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.

100
Thomas Owens

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.

55
Jason Baker

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.

40
TankorSmash

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

35
Gregg Lind

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.

26
Mattias Nilsson

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.

19
Jack M.

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.

16
meder omuraliev

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.

12
Zan Lynx

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

10
Ram

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
7
X. Wang

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

2
johnashu

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.

2
Ryan