Grundlegendes zum "is" -Operator von Python

109

Der isOperator stimmt nicht mit den Werten der Variablen überein, sondern mit den Instanzen selbst.

Was bedeutet das wirklich?

Ich habe zwei Variablen mit dem Namen deklariert xund yin beiden Variablen die gleichen Werte zugewiesen, aber es wird false zurückgegeben, wenn ich den isOperator verwende.

Ich brauche eine Klarstellung. Hier ist mein Code.

x = [1, 2, 3]
y = [1, 2, 3]

print(x is y)  # It prints false!
aniskhan001
quelle
Verwandte Frage stackoverflow.com/questions/38189660/…
Kasravnd

Antworten:

181

Sie haben falsch verstanden, was der isBediener testet. Es wird getestet, ob zwei Variablen auf dasselbe Objekt zeigen , nicht ob zwei Variablen denselben Wert haben.

Aus der Dokumentation für den isBediener :

Die Betreiber isund is notTest für die Objektidentität: x is yist wahr , wenn und nur wenn xund ydasselbe Objekt sind.

Verwenden Sie ==stattdessen den Operator:

print(x == y)

Dies wird gedruckt True. xund ysind zwei separate Listen:

x[0] = 4
print(y)  # prints [1, 2, 3]
print(x == y)   # prints False

Wenn Sie die id()Funktion verwenden , sehen Sie das xund yhaben unterschiedliche Bezeichner:

>>> id(x)
4401064560
>>> id(y)
4401098192

Wenn Sie jedoch zuweisen y, zeigen xbeide auf dasselbe Objekt:

>>> x = y
>>> id(x)
4401064560
>>> id(y)
4401064560
>>> x is y
True

und iszeigt, dass beide das gleiche Objekt sind, gibt es zurück True.

Denken Sie daran, dass Namen in Python nur Bezeichnungen sind, die auf Werte verweisen . Sie können mehrere Namen auf dasselbe Objekt verweisen lassen. issagt Ihnen, ob zwei Namen auf ein und dasselbe Objekt verweisen. ==Gibt an, ob sich zwei Namen auf Objekte beziehen, die denselben Wert haben.

Martijn Pieters
quelle
13
Also A is Bist das gleiche wie id(A) == id(B).
Imallett
2
@imallett: Dies ist ein Proxy für denselben Test, vorausgesetzt, Sie speichern nicht id(A)in einer Variablen und erwarten später, dass variable == id(B)er weiterhin funktioniert. Wenn Aes in der Zwischenzeit gelöscht wurde, Bhätte es denselben Speicherort erhalten können.
Martijn Pieters
1
Kommentare konnten nicht formatiert werden. Aber es gibt eine interessante Sache. :) >>> x = 5 \n>>> y = 5 \n>>> x ist y \nwahr \n>>> x == y \nwahr \n>>>\n
Haranadh
5
Kleine Ganzzahlen werden in CPython interniert, da sie so häufig verwendet werden. Es ist eine Optimierung. x = 5; y = 5; x ist y => Wahr, weil id (x) == id (y). Es ist dasselbe ganzzahlige Objekt, das wiederverwendet wird. Funktioniert in Python, da Ganzzahlen unveränderlich sind. Wenn Sie x = 1.0 tun; y = 1.0 oder x = 9999; y = 9999, es wird nicht dieselbe Identität sein, da Floats und größere Ints nicht interniert sind.
Magnus Lyckå
1
@ MagnusLyckå Es gibt andere Optimierungen, die dazu führen können, dass unveränderliche Objekte zwischengespeichert werden. Wenn Sie Ihr Beispiel beispielsweise in einer neuen Funktion oder zusammen mit einem trennenden Semikolon im interaktiven Interpreter ausführen, werden Sie feststellen, dass diese dieselbe ID haben.
Martijn Pieters
60

Ein anderes Duplikat fragte, warum zwei gleiche Zeichenfolgen im Allgemeinen nicht identisch sind, was hier nicht wirklich beantwortet wird:

>>> x = 'a' 
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False

Warum sind sie nicht die gleiche Saite? Besonders angesichts dessen:

>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True

Lassen Sie uns den zweiten Teil etwas verschieben. Wie konnte der erste wahr sein?

Der Interpreter müsste über eine "interne Tabelle" verfügen, eine Tabelle, die Zeichenfolgenwerte Zeichenfolgenobjekten zuordnet. Jedes Mal, wenn Sie versuchen, eine neue Zeichenfolge mit dem Inhalt zu erstellen 'abc', erhalten Sie dasselbe Objekt zurück. Wikipedia hat eine detailliertere Diskussion darüber, wie Internierung funktioniert.

Und Python hat eine String-Internierungstabelle; Sie können Zeichenfolgen mit der sys.internMethode manuell internieren .

In der Tat ist Python erlaubt automatisch intern jede unveränderlichen Typen, aber nicht erforderlich , dies zu tun. Unterschiedliche Implementierungen führen zu unterschiedlichen Werten.

CPython (die Implementierung, die Sie verwenden, wenn Sie nicht wissen, welche Implementierung Sie verwenden) automatisiert automatisch kleine Ganzzahlen und einige spezielle Singletons wie False, aber keine Zeichenfolgen (oder große Ganzzahlen oder kleine Tupel oder irgendetwas anderes). Sie können dies ziemlich leicht sehen:

>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False

OK, aber warum waren zund widentisch?

Das ist nicht der Interpreter, der automatisch interniert, sondern die Compiler-Faltwerte.

Wenn das gleiche Kompilierung-String zweimal im selben Modul erscheint (was genau das bedeutet , ist schwer zu definieren-es ist nicht das gleiche wie ein Zeichenfolgenliteral, weil r'abc', 'abc'und 'a' 'b' 'c'sind alle verschieden Literale aber die gleiche Zeichenfolge, aber leicht zu verstehen intuitiv) erstellt der Compiler nur eine Instanz der Zeichenfolge mit zwei Referenzen.

Der Compiler kann sogar noch weiter gehen: Er 'ab' + 'c'kann 'abc'vom Optimierer konvertiert werden. In diesem Fall kann er zusammen mit einer 'abc'Konstanten im selben Modul gefaltet werden.

Auch dies ist Python erlaubt, muss aber nicht. In diesem Fall faltet CPython jedoch immer kleine Zeichenfolgen (und z. B. auch kleine Tupel). (Obwohl der Statement-by-Statement-Compiler des interaktiven Interpreters nicht die gleiche Optimierung ausführt wie der Compiler für jeweils einzelne Module, werden interaktiv nicht genau die gleichen Ergebnisse angezeigt.)


Was sollten Sie als Programmierer dagegen tun?

Naja nichts. Sie haben fast nie Grund zur Sorge, wenn zwei unveränderliche Werte identisch sind. Wenn Sie wissen möchten, wann Sie a is banstelle von verwenden können a == b, stellen Sie die falsche Frage. Nur immer verwenden, a == baußer in zwei Fällen:

  • Für besser lesbare Vergleiche mit den Singleton-Werten wie x is None.
  • Bei veränderlichen Werten, wenn Sie wissen müssen, ob sich eine Mutation xauf die auswirkt y.
abarnert
quelle
1
Hervorragende Erklärung, insbesondere Ihr Rat am Ende.
DavidG
Vielen Dank für diese ausführliche Erklärung. Weiß jemand: Wenn wund zaufgrund der Compiler-Faltwerte identisch sind, warum funktioniert dies auch in der REPL, selbst wenn id()die Referenzen überprüft werden? Verwenden der REPL auf Python 3.7
Chi-Chi
8

isGibt nur dann true zurück, wenn es sich tatsächlich um dasselbe Objekt handelt. Wenn sie gleich wären, würde sich auch eine Änderung an der einen in der anderen zeigen. Hier ist ein Beispiel für den Unterschied.

>>> x = [1, 2, 3]
>>> y = [1, 2, 3]
>>> print x is y
False
>>> z = y
>>> print y is z
True
>>> print x is z
False
>>> y[0] = 5
>>> print z
[5, 2, 3]
Mark Ransom
quelle
8

Diese Analogie könnte durch eine doppelte Frage ausgelöst werden :

# - Darling, I want some pudding!
# - There is some in the fridge.

pudding_to_eat = fridge_pudding
pudding_to_eat is fridge_pudding
# => True

# - Honey, what's with all the dirty dishes?
# - I wanted to eat pudding so I made some. Sorry about the mess, Darling.
# - But there was already some in the fridge.

pudding_to_eat = make_pudding(ingredients)
pudding_to_eat is fridge_pudding
# => False
Amadan
quelle
3
Könnte nur ein persönlicher Geschmack sein (kein Wortspiel beabsichtigt), aber ich fand diese Analogie eher verwirrend als hilfreich und habe mich dazu gebracht, Pudding zu essen, wenn ich keinen in meinem Kühlschrank habe :( Ich denke, Mark Ransoms Antwort ist zwar langweiliger, aber langweiliger wahrscheinlich lehrreicher
Tom Close
1
@ TomClose: Es gibt viele gute Antworten auf diese Frage, genug, um Platz für Leichtsinn zu schaffen. Ich möchte auch Pudding.
Amadan
5

isund is notsind die beiden Identitätsoperatoren in Python. isDer Operator vergleicht nicht die Werte der Variablen, sondern die Identitäten der Variablen. Bedenken Sie:

>>> a = [1,2,3]
>>> b = [1,2,3]
>>> hex(id(a))
'0x1079b1440'
>>> hex(id(b))
'0x107960878'
>>> a is b
False
>>> a == b
True
>>>

Das obige Beispiel zeigt Ihnen, dass die Identität (kann auch die Speicheradresse in Cpython sein) für beide aund b(obwohl ihre Werte gleich sind) unterschiedlich ist. Wenn Sie sagen, dass a is bdies aufgrund der Nichtübereinstimmung der Identitäten beider Operanden falsch ist, ist dies der Grund. Wenn Sie jedoch sagen a == b, wird true zurückgegeben, da die ==Operation nur überprüft, ob beiden Operanden der gleiche Wert zugewiesen wurde.

Interessantes Beispiel (für die Extraklasse):

>>> del a
>>> del b
>>> a = 132
>>> b = 132
>>> hex(id(a))
'0x7faa2b609738'
>>> hex(id(b))
'0x7faa2b609738'
>>> a is b
True
>>> a == b
True
>>>

In dem obigen Beispiel, obwohl aund bsind zwei verschiedene Variablen, a is bzurückgegeben True. Dies liegt daran , die Art der aheißt , intdie ein unveränderliches Objekt ist. Python (ich denke, um Speicherplatz zu sparen) hat also dasselbe Objekt zugewiesen, bals es mit demselben Wert erstellt wurde. In diesem Fall stimmten die Identitäten der Variablen überein und a is bstellten sich als solche heraus True.

Dies gilt für alle unveränderlichen Objekte:

>>> del a
>>> del b
>>> a = "asd"
>>> b = "asd"
>>> hex(id(a))
'0x1079b05a8'
>>> hex(id(b))
'0x1079b05a8'
>>> a is b
True
>>> a == b
True
>>>

Hoffentlich hilft das.

Gixxer
quelle
Das ist ein wirklich schönes Beispiel. danke für detaillierte info.
Haranadh
Versuchen Sie jedoch a = 123456789 b = 123456789
user2183078
Alles, was kleiner -5oder höher als 256in Python ist, ist falsch. Python speichert Zahlen im Bereich [-5, 256] zwischen.
klug
Wie Sie zeigen, werden nicht alle unveränderlichen Objekte gemeinsam genutzt. Dies ist eine Optimierung, die von der Python-Laufzeit für einige Objekte angewendet wird, für andere jedoch nicht. Der Prozess des Teilens kleiner Ganzzahlen ist gut dokumentiert, aber ich denke nicht, dass es sich um das Internieren von Zeichenfolgen handelt .
Mark Ransom vor
4

x is yist dasselbe wie das id(x) == id(y)Vergleichen der Identität von Objekten.

Wie @ tomasz-kurgan im Kommentar unten ausgeführt hat is, verhält sich der Operator bei bestimmten Objekten ungewöhnlich.

Z.B

>>> class A(object):
...   def foo(self):
...     pass
... 
>>> a = A()
>>> a.foo is a.foo
False
>>> id(a.foo) == id(a.foo)
True

Ref;
https://docs.python.org/2/reference/expressions.html#is-not
https://docs.python.org/2/reference/expressions.html#id24

Nizam Mohamed
quelle
Nicht, tut es nicht. In den meisten Fällen verhält es sich möglicherweise ähnlich, aber es ist nicht immer wahr. Siehe dies - ganz unten auf der Seite, Punkt 6:> (...), stellen Sie möglicherweise ein scheinbar ungewöhnliches Verhalten bei bestimmten Verwendungen des Operators is fest , z. B. bei Vergleichen zwischen Instanzmethoden oder Konstanten und dem minimalen Arbeitsbeispiel : `Klasse A (Objekt): def foo (Selbst): pass a = A () print a.foo ist a.foo print id (a.foo) == id (a.foo)`
Tomasz Kurgan
3

Da können Sie hier eine kleine ganze Zahl überprüfen. Zahlen über 257 sind keine kleinen Ints, daher wird sie als anderes Objekt berechnet.

==In diesem Fall ist es besser, stattdessen zu verwenden .

Weitere Informationen finden Sie hier: http://docs.python.org/2/c-api/int.html

CS Gamer
quelle
2

X zeigt auf ein Array, Y zeigt auf ein anderes Array. Diese Arrays sind identisch, aber der isOperator betrachtet die Zeiger, die nicht identisch sind.

Neko
quelle
5
Python hat keine Zeiger. Sie müssen Ihre Terminologie verschärfen.
David Heffernan
3
Es funktioniert intern, genau wie Java und so viele andere Sprachen. Tatsächlich iszeigt die Funktionalität des Bedieners dies.
Neko
5
Die Implementierungsdetails sind nicht wichtig. Die Dokumentation verwendet die Terminologie "Objektidentität". Das solltest du auch. "Der Operator ist und ist kein Test für die Objektidentität: x ist y ist genau dann wahr, wenn x und y dasselbe Objekt sind. X ist nicht y ergibt den inversen Wahrheitswert."
David Heffernan
1
@Neko: CPython verwendet intern Zeiger. Aber offensichtlich verwenden Jython (in Java implementiert) und PyPy (in einer Teilmenge von Python implementiert) keine Zeiger. In PyPy haben einige Objekte nicht einmal eine, idwenn Sie nicht danach fragen.
Abarnert
1

Es vergleicht die Objektidentität, dh ob sich die Variablen auf dasselbe Objekt im Speicher beziehen. Es ist wie ==in Java oder C (beim Vergleichen von Zeigern).

Mipadi
quelle
1

Ein einfaches Beispiel mit Früchten

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist is newfruitlist )
print ( fruitlist is verynewfruitlist )
print ( newfruitlist is verynewfruitlist )

Ausgabe:

True
False
False

Wenn du es versuchst

fruitlist = [" apple ", " banana ", " cherry ", " durian "]
newfruitlist = fruitlist
verynewfruitlist = fruitlist [:]
print ( fruitlist == newfruitlist )
print ( fruitlist == verynewfruitlist )
print ( newfruitlist == verynewfruitlist )

Die Ausgabe ist unterschiedlich:

True
True
True

Dies liegt daran, dass der Operator == nur den Inhalt der Variablen vergleicht. Um die Identitäten von 2 Variablen zu vergleichen, verwenden Sie das is Operator

So drucken Sie die Identifikationsnummer:

print ( id( variable ) )
ForsakenOne
quelle
-3

Der isBetreiber ist nichts anderes als eine englische Version von ==. Da die IDs der beiden Listen unterschiedlich sind, ist die Antwort falsch. Du kannst es versuchen:

a=[1,2,3]
b=a
print(b is a )#True

* Weil die IDs beider Listen gleich wären

Aadit
quelle
isist ‚eine englische Version nicht ==
David Buck