Comprensione dell'operatore "is" di Python


110

L' isoperatore non corrisponde ai valori delle variabili, ma alle istanze stesse.

Cosa significa veramente?

Ho dichiarato due variabili denominate xe yassegnando gli stessi valori in entrambe le variabili, ma restituisce false quando uso l' isoperatore.

Ho bisogno di un chiarimento. Ecco il mio codice.

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

print(x is y)  # It prints false!

Risposte:


181

Hai frainteso quello che verifica l' isoperatore. Verifica se due variabili puntano lo stesso oggetto , non se due variabili hanno lo stesso valore.

Dalla documentazione per l' isoperatore :

Gli operatori ise is nottest per l'identità dell'oggetto: x is yè vero se e solo se xe ysono lo stesso oggetto.

Utilizza ==invece l' operatore:

print(x == y)

Questo stampa True. xe ysono due elenchi separati :

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

Se utilizzi la id()funzione , la vedrai xe yavrai identificatori diversi:

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

ma se dovessi assegnare ya, xentrambi puntano allo stesso oggetto:

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

e ismostra che entrambi sono lo stesso oggetto, ritorna True.

Ricorda che in Python i nomi sono solo etichette che fanno riferimento a valori ; puoi fare in modo che più nomi puntino allo stesso oggetto. isti dice se due nomi puntano allo stesso oggetto. ==ti dice se due nomi si riferiscono a oggetti che hanno lo stesso valore.


13
Quindi, A is Bè lo stesso di id(A) == id(B).
imallett

2
@imallett: è un proxy per lo stesso test, a condizione che non si memorizzi id(A)in una variabile e che in seguito si preveda che variable == id(B)funzioni ancora; se è Astato cancellato nel frattempo, Bavrebbe potuto essere assegnata la stessa posizione di memoria.
Martijn Pieters

1
Impossibile formattare nei commenti. Ma c'è una cosa interessante. :) >>> x = 5 \n>>> y = 5 \n>>> x è y \nVero \n>>> x == y \nVero \n>>>\n
Haranadh

5
Piccoli numeri interi sono internati in CPython poiché sono usati così spesso. È un'ottimizzazione. x = 5; y = 5; x è y => Vero perché id (x) == id (y). È lo stesso oggetto intero che viene riutilizzato. Funziona in Python poiché i numeri interi sono immutabili. Se fai x = 1.0; y = 1.0 o x = 9999; y = 9999, non sarà la stessa identità, perché i float e gli int più grandi non sono interni.
Magnus Lyckå,

1
@ MagnusLyckå ci sono altre ottimizzazioni che possono causare la memorizzazione nella cache di oggetti immutabili. Ad esempio, se esegui il tuo esempio in una nuova funzione o insieme a un punto e virgola di separazione nell'interprete interattivo, scoprirai che anche loro hanno lo stesso ID.
Martijn Pieters

60

Un altro duplicato chiedeva perché due stringhe uguali in genere non sono identiche, il che non è davvero risposto qui:

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

Allora, perché non sono la stessa stringa? Soprattutto dato questo:

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

Rimandiamo un po 'la seconda parte. Come potrebbe essere vero il primo?

L'interprete dovrebbe avere una "tabella interna", una tabella che associa i valori delle stringhe agli oggetti stringa, così ogni volta che provi a creare una nuova stringa con il contenuto 'abc', ritorna lo stesso oggetto. Wikipedia ha una discussione più dettagliata su come funziona lo stage.

E Python ha una tabella interna di stringhe; puoi internare manualmente le stringhe con il sys.internmetodo.

In effetti, Python può internare automaticamente qualsiasi tipo immutabile, ma non è obbligato a farlo. Diverse implementazioni interneranno valori diversi.

CPython (l'implementazione che stai usando se non sai quale implementazione stai usando) auto-interns piccoli interi e alcuni singleton speciali come False, ma non stringhe (o numeri interi grandi, o piccole tuple o qualsiasi altra cosa). Puoi vederlo abbastanza facilmente:

>>> 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, ma perché erano ze widentici?

Non è l'interprete che esegue automaticamente l'internamento, sono i valori di ripiegamento del compilatore.

Se la stessa stringa di compilazione appare due volte nello stesso modulo (che cosa esattamente questo significa è difficile da definire, non è la stessa cosa di un letterale di stringa, perché r'abc', 'abc'e 'a' 'b' 'c'sono tutte letterali diverse ma la stessa stringa, ma facile da capire intuitivamente), il compilatore creerà solo un'istanza della stringa, con due riferimenti.

In effetti, il compilatore può andare anche oltre: 'ab' + 'c'può essere convertito in 'abc'dall'ottimizzatore, nel qual caso può essere piegato insieme a una 'abc'costante nello stesso modulo.

Di nuovo, questo è qualcosa che Python è consentito ma non è tenuto a fare. Ma in questo caso, CPython piega sempre piccole stringhe (e anche, ad esempio, piccole tuple). (Sebbene il compilatore istruzione per istruzione dell'interprete interattivo non esegua la stessa ottimizzazione del compilatore modulo alla volta, quindi non vedrai esattamente gli stessi risultati in modo interattivo.)


Allora, cosa dovresti fare al riguardo come programmatore?

Beh ... niente. Non hai quasi mai motivo di preoccuparti se due valori immutabili sono identici. Se vuoi sapere quando puoi usare a is binvece di a == b, stai facendo la domanda sbagliata. Basta usare sempre a == btranne in due casi:

  • Per confronti più leggibili con i valori singleton come x is None.
  • Per i valori modificabili, quando è necessario sapere se la modifica xinfluirà su y.

1
Ottima spiegazione, soprattutto il tuo consiglio alla fine.
DavidG

Grazie per quella spiegazione dettagliata. Qualcuno sa: se we zsono identici a causa dei valori di ripiegamento del compilatore, perché questo funziona anche nel REPL, anche usando id()per controllare i riferimenti? Utilizzo di REPL su Python 3.7
Chi-chi

8

isrestituisce true solo se sono effettivamente lo stesso oggetto. Se fossero gli stessi, un cambiamento in uno si manifesterebbe anche nell'altro. Ecco un esempio della differenza.

>>> 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]

8

Spinto da una domanda duplicata , questa analogia potrebbe funzionare:

# - 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

3
Potrebbe essere solo un gusto personale (nessun gioco di parole) ma ho trovato questa analogia più confusa che utile e mi ha fatto venire voglia di mangiare budino quando non ne ho nel frigo :( Penso che la risposta di Mark Ransom, sebbene più noiosa, sia probabilmente più istruttivo
Tom Close

1
@ TomClose: ci sono molte belle risposte a questa domanda, abbastanza da lasciare spazio alla leggerezza. Inoltre, voglio anche il budino.
Amadan

5

ise is notsono i due operatori di identità in Python. isL'operatore non confronta i valori delle variabili, ma confronta le identità delle variabili. Considera questo:

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

L'esempio sopra mostra che l'identità (può anche essere l'indirizzo di memoria in Cpython) è diversa per entrambi ae b(anche se i loro valori sono gli stessi). Questo è il motivo per cui quando dici a is bche restituisce falso a causa della mancata corrispondenza nelle identità di entrambi gli operandi. Tuttavia, quando dici a == b, restituisce vero perché l' ==operazione verifica solo se entrambi gli operandi hanno lo stesso valore assegnato a loro.

Esempio interessante (per il voto extra):

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

Nell'esempio precedente, anche se ae bsono due variabili diverse, vengono a is brestituite True. Questo perché il tipo di aè intche è un oggetto immutabile. Quindi python (immagino per risparmiare memoria) ha allocato lo stesso oggetto bquando è stato creato con lo stesso valore. Quindi, in questo caso, le identità delle variabili corrispondevano e a is bsi sono rivelate True.

Questo si applicherà a tutti gli oggetti immutabili:

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

Spero che aiuti.


questo è un vero bell'esempio. grazie per informazioni dettagliate.
Haranadh

Ma prova a = 123456789 b = 123456789
user2183078

Tutto ciò che è inferiore -5o superiore 256a Python sarà False. Python memorizza nella cache i numeri nell'intervallo [-5, 256].
smart

Non tutti gli oggetti immutabili verranno condivisi come mostrato, questa è un'ottimizzazione applicata dal runtime Python per alcuni oggetti ma non per altri. Il processo di condivisione di piccoli numeri interi è ben documentato, ma non credo sia per l'internamento di stringhe .
Mark Ransom

4

x is yè uguale a id(x) == id(y)confrontare l'identità degli oggetti.

Come ha sottolineato @ tomasz-kurgan nel commento di seguito, l' isoperatore si comporta in modo insolito con determinati oggetti.

Per esempio

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


No, non lo fa. Potrebbe comportarsi in modo simile nella maggior parte dei casi, ma non è sempre vero. Vedi questo - in fondo alla pagina, punto 6 .:> (...), potresti notare un comportamento apparentemente insolito in alcuni usi dell'operatore is , come quelli che implicano confronti tra metodi di istanza o costanti E l'esempio di lavoro minimo : `class A (oggetto): def foo (self): pass a = A () print a.foo is a.foo print id (a.foo) == id (a.foo)`
Tomasz Kurgan

3

Come puoi controllare qui a piccoli numeri interi. I numeri superiori a 257 non sono piccoli interi, quindi vengono calcolati come un oggetto diverso.

È meglio usare ==invece in questo caso.

Ulteriori informazioni sono qui: http://docs.python.org/2/c-api/int.html


2

X punta a una matrice, Y punta a una matrice diversa. Questi array sono identici, ma l' isoperatore esaminerà quei puntatori, che non sono identici.


5
Python non ha puntatori. Devi rafforzare la tua terminologia.
David Heffernan

3
Lo fa internamente, proprio come Java e tanti altri linguaggi. In effetti, la isfunzionalità dell'operatore lo dimostra.
Neko

5
I dettagli di implementazione non sono ciò che conta. La documentazione utilizza la terminologia "identità dell'oggetto". Quindi dovresti. "Gli operatori sono e non sono test per l'identità dell'oggetto: x è y è vero se e solo se xey sono lo stesso oggetto. X è non y restituisce il valore di verità inverso."
David Heffernan

1
@Neko: CPython utilizza internamente i puntatori. Ma ovviamente Jython (implementato in Java) e PyPy (implementato in un sottoinsieme di Python) non usano puntatori. In PyPy, alcuni oggetti non avranno nemmeno un a idmeno che tu non lo chieda.
abarnert

1

Confronta l'identità dell'oggetto, ovvero se le variabili si riferiscono allo stesso oggetto in memoria. È come ==in Java o C (quando si confrontano i puntatori).


1

Un semplice esempio con la frutta

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

Produzione:

True
False
False

Se provi

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

L'output è diverso:

True
True
True

Questo perché l'operatore == confronta solo il contenuto della variabile. Per confrontare le identità di 2 variabili utilizzare l' operatore is

Per stampare il numero di identificazione:

print ( id( variable ) )

-3

L' isoperatore non è altro che una versione inglese di ==. Poiché gli ID dei due elenchi sono diversi, la risposta è falsa. Puoi provare:

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

* Perché gli ID di entrambi gli elenchi sarebbero gli stessi


isnon è "una versione inglese di =="
David Buck
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.