C'è una differenza tra “==” e “is”?


630

Il mio Google-fu mi ha fallito.

In Python, i seguenti due test sono equivalenti?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

Questo vale per gli oggetti in cui si confronteranno le istanze (per listesempio)?

Bene, quindi questo tipo di risposte risponde alla mia domanda:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

Quindi ==test valuta dove istest per vedere se sono lo stesso oggetto?

Risposte:


928

isrestituirà Truese due variabili puntano allo stesso oggetto, ==se gli oggetti a cui fanno riferimento le variabili sono uguali.

>>> a = [1, 2, 3]
>>> b = a
>>> b is a 
True
>>> b == a
True

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

Nel tuo caso, il secondo test funziona solo perché Python memorizza nella cache piccoli oggetti interi, che sono dettagli di implementazione. Per numeri interi più grandi, questo non funziona:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

Lo stesso vale per i letterali stringa:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Vedi anche questa domanda .


2
Ho scoperto che: echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - fooUscita: False True False.
ahuigo,

Mi hai perso con la b = a[:]parte copia dell'elenco degli operatori delle sezioni, quindi ho modificato la tua risposta per avere un commento lì. Sembra che ho appena raggiunto la soglia per non dover rivedere le mie modifiche prima che vengano applicate, quindi speriamo che sia bello per te. Indipendentemente da ciò, ecco un utile riferimento su come copiare gli elenchi che mi sono imbattuto e ho dovuto fare riferimento per capire cosa stavi facendo: stackoverflow.com/a/2612815/4561887
Gabriel Staples

Un altro modo per dimostrare la differenza è confrontando oggetti di tipi diversi, che ovviamente non possono mai essere lo stesso oggetto ma comunque uguali quando si usa ==. Quindi, 5.0ad esempio, è un valore in virgola mobile, mentre 5è un numero intero. Ma 5.0 == 5tornerà comunque Trueperché rappresentano lo stesso valore. In termini di prestazioni e dattilografia, isviene sempre testato dall'interprete confrontando gli indirizzi di memoria dell'operando, mentre con ==esso spetta all'oggetto decidere se si definisce uguale a qualcos'altro.
Bachsau,

3
1000 is 10**3restituisce True in Python 3.7 poiché 10 ** 3 è type int. Ma 1000 is 1e3restituisce False poiché 1e3 è di tipo float.
Ahmed Fasih,

@AhmedFasih La validità o meno 1000 is 10**3dipende dall'implementazione e dipende dal compilatore che pre-valuta l'espressione 10**3. x=10; 1000 is x**3valuta False.
Chepner,

313

C'è una semplice regola empirica per dirti quando usare ==o is.

  • ==è per l' uguaglianza di valore . Usalo quando vuoi sapere se due oggetti hanno lo stesso valore.
  • isè per l' uguaglianza di riferimento . Usalo quando vuoi sapere se due riferimenti si riferiscono allo stesso oggetto.

In generale, quando si confronta qualcosa con un tipo semplice, di solito si verifica l' uguaglianza di valore , quindi è necessario utilizzarlo ==. Ad esempio, l'intenzione del tuo esempio è probabilmente quella di verificare se x abbia un valore uguale a 2 ( ==), non se xsi riferisca letteralmente allo stesso oggetto di 2.


Qualcos'altro da notare: a causa del modo in cui funziona l'implementazione di riferimento di CPython, otterrai risultati imprevisti e incoerenti se usi erroneamente isper confrontare per l'uguaglianza di riferimento sugli interi:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

È praticamente quello che ci aspettavamo: ae bhanno lo stesso valore, ma sono entità distinte. Ma che dire di questo?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

Ciò non è coerente con il risultato precedente. Cosa sta succedendo qui? Si scopre che l'implementazione di riferimento di Python memorizza nella cache oggetti interi nell'intervallo -5..256 come istanze singleton per motivi di prestazioni. Ecco un esempio che dimostra questo:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

Questa è un'altra ragione ovvia da non usare is: il comportamento è lasciato alle implementazioni quando lo si utilizza erroneamente per l'uguaglianza di valore.


Per quanto riguarda il primo esempio di a=500e b=500, volevo solo sottolineare che se si imposta ae bsu un intervallo tra [-5, 256], a is beffettivamente ritorna True. Maggiori informazioni qui: stackoverflow.com/q/306313/7571052
AsheKetchum

1
@AsheKetchum, sì, nota che ho scritto "Si scopre che l'implementazione di riferimento di Python memorizza nella cache oggetti interi nell'intervallo -5..256 come istanze singleton per motivi di prestazioni."
John Feminella,

34

==determina se i valori sono uguali, mentre isdetermina se sono esattamente lo stesso oggetto.


32

C'è una differenza tra ==e isin Python?

Sì, hanno una differenza molto importante.

==: controlla l'uguaglianza - la semantica è che gli oggetti equivalenti (che non sono necessariamente lo stesso oggetto) testeranno come uguali. Come dice la documentazione :

Gli operatori <,>, ==,> =, <= e! = Confrontano i valori di due oggetti.

is: controlla l'identità - la semantica è che l'oggetto (come tenuto in memoria) è l'oggetto. Ancora una volta, la documentazione dice :

Gli operatori ise is nottest per l'identità dell'oggetto: x is yè vero se e solo se xe ysono lo stesso oggetto. L'identità dell'oggetto viene determinata utilizzando la id()funzione. x is not yproduce il valore della verità inversa.

Pertanto, il controllo dell'identità è uguale al controllo dell'uguaglianza degli ID degli oggetti. Questo è,

a is b

equivale a:

id(a) == id(b)

dove idè la funzione incorporata che restituisce un numero intero che "è garantito essere unico tra oggetti esistenti simultaneamente" (vedi help(id)) e dove ae bsono oggetti arbitrari.

Altre istruzioni per l'uso

Dovresti usare questi confronti per la loro semantica. Utilizzare isper verificare l'identità e ==per verificare l'uguaglianza.

Quindi, in generale, usiamo isper verificare l'identità. Questo è di solito utile quando stiamo verificando un oggetto che dovrebbe esistere solo una volta in memoria, indicato come "singleton" nella documentazione.

I casi d'uso per isincludono:

  • None
  • valori enum (quando si usano Enums dal modulo enum)
  • di solito moduli
  • di solito oggetti di classe risultanti dalle definizioni di classe
  • di solito oggetti funzione derivanti dalle definizioni delle funzioni
  • qualsiasi altra cosa che dovrebbe esistere solo una volta in memoria (tutti i singoli, in generale)
  • un oggetto specifico che si desidera per identità

I casi d'uso usuali per ==includono:

  • numeri, compresi numeri interi
  • stringhe
  • liste
  • imposta
  • dizionari
  • oggetti mutabili personalizzati
  • altri oggetti immutabili incorporati, nella maggior parte dei casi

Il caso di uso generale, ancora una volta, per ==, è l'oggetto che si desidera non può essere lo stesso oggetto, invece può essere un equivalente uno

PEP 8 direzioni

PEP 8, la guida ufficiale dello stile Python per la libreria standard menziona anche due casi d'uso peris :

I confronti con i singleton come Nonedovrebbero sempre essere fatti con iso is not, mai, gli operatori di uguaglianza.

Inoltre, if xfai attenzione a scrivere quando intendi davvero if x is not None, ad esempio quando si verifica se una variabile o un argomento predefinito None è impostato su un altro valore. L'altro valore potrebbe avere un tipo (come un contenitore) che potrebbe essere falso in un contesto booleano!

Inferenza dell'uguaglianza dall'identità

Se isè vero, l'uguaglianza di solito può essere dedotta - logicamente, se un oggetto è se stesso, allora dovrebbe essere testato come equivalente a se stesso.

Nella maggior parte dei casi questa logica è vera, ma si basa sull'implementazione del __eq__metodo speciale. Come dicono i documenti ,

Il comportamento predefinito per il confronto di uguaglianza ( ==e !=) si basa sull'identità degli oggetti. Quindi, il confronto di uguaglianza di istanze con la stessa identità provoca uguaglianza e il confronto di uguaglianza di istanze con identità diverse provoca disuguaglianza. Una motivazione per questo comportamento predefinito è il desiderio che tutti gli oggetti siano riflessi (ovvero x è y implica x == y).

e nell'interesse della coerenza, raccomanda:

Il confronto di uguaglianza dovrebbe essere riflessivo. In altre parole, gli oggetti identici dovrebbero confrontare uguale:

x is y implica x == y

Possiamo vedere che questo è il comportamento predefinito per gli oggetti personalizzati:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

Anche il contrappunto è di solito vero: se qualcosa risulta non uguale, di solito si può dedurre che non sono lo stesso oggetto.

Poiché i test per l'uguaglianza possono essere personalizzati, questa inferenza non è sempre valida per tutti i tipi.

Un'eccezione

Un'eccezione notevole è nan- si verifica sempre come non uguale a se stesso:

>>> nan = float('nan')
>>> nan
nan
>>> nan is nan
True
>>> nan == nan           # !!!!!
False

Il controllo dell'identità può essere molto più rapido del controllo dell'uguaglianza (che potrebbe richiedere un controllo ricorsivo dei membri).

Ma non può essere sostituito per l'uguaglianza in cui è possibile trovare più di un oggetto come equivalente.

Si noti che il confronto dell'uguaglianza di elenchi e tuple presuppone che l'identità degli oggetti sia uguale (poiché si tratta di un controllo rapido). Ciò può creare contraddizioni se la logica è incoerente, come per nan:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

Un racconto cautelativo:

La domanda sta tentando di utilizzare isper confrontare numeri interi. Non si deve supporre che un'istanza di un numero intero sia la stessa istanza di una ottenuta da un altro riferimento. Questa storia spiega perché.

Un commentatore aveva un codice che si basava sul fatto che piccoli numeri interi (da -5 a 256 inclusi) sono singleton in Python, invece di verificare l'uguaglianza.

Wow, questo può portare ad alcuni bug insidiosi. Avevo del codice che controllava se a è b, che funzionava come volevo perché aeb sono in genere numeri piccoli. Il bug si è verificato solo oggi, dopo sei mesi di produzione, perché aeb erano finalmente abbastanza grandi da non poter essere memorizzati nella cache. - gwg

Ha funzionato nello sviluppo. Potrebbe aver superato alcuni unittest.

E ha funzionato in produzione - fino a quando il codice non ha verificato un numero intero maggiore di 256, a quel punto ha fallito nella produzione.

Si tratta di un errore di produzione che potrebbe essere stato rilevato durante la revisione del codice o eventualmente con un controllo di stile.

Vorrei sottolineare: non utilizzare isper confrontare numeri interi.


"Non usare è affatto" sarebbe anche una buona regola. L'idioma is Noneè un'eccezione, ma anche quello ha detto che == Nonefunziona ...
Jean-François Fabre

@ Jean-FrançoisFabre Un'altra eccezione: la documentazione ufficiale sembra raccomandare l'utilizzo isper confrontare Enums.
Arthur,

@Arthur Ho aggiunto un elenco di casi d'uso ...
Aaron Hall

19

Qual è la differenza tra ise ==?

==e issono un confronto diverso! Come altri hanno già detto:

  • == confronta i valori degli oggetti.
  • is confronta i riferimenti degli oggetti.

In Python i nomi si riferiscono ad oggetti, ad esempio in questo caso value1e si value2riferiscono a intun'istanza che memorizza il valore 1000:

value1 = 1000
value2 = value1

inserisci qui la descrizione dell'immagine

Perché si value2riferisce allo stesso oggetto ise ==darà True:

>>> value1 == value2
True
>>> value1 is value2
True

Nel seguente esempio i nomi value1e si value2riferiscono a intistanze diverse , anche se entrambi memorizzano lo stesso numero intero:

>>> value1 = 1000
>>> value2 = 1000

inserisci qui la descrizione dell'immagine

Poiché ==verrà memorizzato lo stesso valore (intero) True, ecco perché viene spesso chiamato "confronto di valori". Tuttavia istornerà Falseperché si tratta di oggetti diversi:

>>> value1 == value2
True
>>> value1 is value2
False

Quando usare quale?

Generalmente isè un confronto molto più veloce. Ecco perché CPython memorizza nella cache (o forse il riutilizzo sarebbe il termine migliore) determinati oggetti come piccoli numeri interi, alcune stringhe, ecc. Ma questo dovrebbe essere trattato come un dettaglio di implementazione che potrebbe (anche se improbabile) cambiare in qualsiasi momento senza preavviso.

Dovresti usare solois se:

  • voglio verificare se due oggetti sono davvero lo stesso oggetto (non solo lo stesso "valore"). Un esempio può essere se si utilizza un oggetto singleton come costante.
  • vuoi confrontare un valore con una costante Python . Le costanti in Python sono:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • classi (ad esempio int is into int is float)
    • potrebbero esserci costanti aggiuntive nei moduli integrati o moduli di terze parti. Ad esempio np.ma.maskeddal modulo NumPy)

In ogni altro caso dovresti usare== per verificare l'uguaglianza.

Posso personalizzare il comportamento?

C'è un aspetto ==che non è già stato menzionato nelle altre risposte: fa parte del "Modello di dati" di Pythons . Ciò significa che il suo comportamento può essere personalizzato utilizzando il __eq__metodo. Per esempio:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

Questo è solo un esempio artificiale per illustrare che il metodo è davvero chiamato:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

Si noti che per impostazione predefinita (se non è __eq__possibile trovare altre implementazioni nella classe o nelle superclassi) __eq__utilizza is:

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

Quindi è davvero importante implementare __eq__se si desidera "di più" di un semplice confronto di riferimento per le classi personalizzate!

D'altra parte non è possibile personalizzare i iscontrolli. Comparerà sempre solo se hai lo stesso riferimento.

Questi confronti restituiranno sempre un valore booleano?

Perché __eq__può essere implementato nuovamente o sovrascritto, non è limitato a return Trueo False. Si potrebbe restituire nulla (ma nella maggior parte dei casi deve restituire un valore booleano!).

Ad esempio con gli array NumPy ==restituirà un array:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

Ma i iscontrolli torneranno sempre Trueo False!


1 Come ha affermato Aaron Hall nei commenti:

Generalmente non dovresti fare alcuno is Trueo is Falsecontrolli perché normalmente si usano questi "controlli" in un contesto che converte implicitamente la condizione in un valore booleano (ad esempio in ifun'istruzione). Quindi fare il is Trueconfronto e il cast booleano implicito significa fare più lavoro che limitarsi al cast booleano - e ti limiti ai booleani (che non sono considerati pitonici).

Come menziona PEP8:

Non confrontare i valori booleani con Trueo Falseutilizzando ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:

2
Dovrò essere in disaccordo sulla tua affermazione per confrontare "costanti" con is- i nomi che indicano i booleani dovrebbero essere controllati con un contesto booleano - come if __debug__:o if not __debug__:. Non si dovrebbe mai fare if __debug__ is True:o if __debug__ == True:- inoltre, una costante è semplicemente un valore semantico costante, non un singleton, quindi verificare isin quel caso non è semanticamente corretto. Ti sfido a trovare una fonte a supporto delle tue affermazioni - non credo che troverai una.
Aaron Hall

@AaronHall Cosa ti fa pensare che le costanti non siano singole? Nota che solo None, True, Falsee __debug__sono quello che si chiama "valore semantico costante", perché non possono essere riassegnati. Ma sono tutti dei singoli.
MSeifert,

Leggi PEP 8 - Ctrl-F e cerca la parola "peggio". - Se non sei inflessibile, useresti self.assertTrue
Aaron Hall

@AaronHall In alcune circostanze si ha realmente bisogno l' is Trueo if Falseassegno (ma sì, questi sono piuttosto rare - ma se le fate si può fare utilizzando is). Ecco perché anche CPython li usa a volte (ad esempio qui o qui )
MSeifert

19

Sono completamente diversi . isverifica l'identità dell'oggetto, mentre ==verifica l'uguaglianza (una nozione che dipende dai tipi di due operandi).

È solo una coincidenza fortunata che " is" sembra funzionare correttamente con numeri interi piccoli (ad es. 5 == 4 + 1). Questo perché CPython ottimizza la memorizzazione degli interi nell'intervallo (da -5 a 256) rendendoli singoli . Questo comportamento è totalmente dipendente dall'implementazione e non è garantito che sia preservato in tutte le forme di operazioni di trasformazione minori.

Ad esempio, Python 3.5 crea anche singoli stringhe brevi, ma il loro taglio interrompe questo comportamento:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False


6

La tua risposta è corretta L' isoperatore confronta l'identità di due oggetti. L' ==operatore confronta i valori di due oggetti.

L'identità di un oggetto non cambia mai dopo che è stata creata; puoi pensarlo come l'indirizzo dell'oggetto in memoria.

Puoi controllare il comportamento di confronto dei valori degli oggetti definendo un __cmp__metodo o un metodo di confronto avanzato come __eq__.



3

In poche parole, iscontrolla se due riferimenti puntano allo stesso oggetto o meno. ==controlla se due oggetti hanno lo stesso valore o meno.

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 

2

Come diceva John Feminella, il più delle volte userete == e! = Perché il vostro obiettivo è confrontare i valori. Vorrei solo classificare ciò che faresti per il resto del tempo:

Esiste una sola istanza di NoneType, ovvero None è un singleton. Di conseguenza foo == Nonee foo is Nonesignificano lo stesso. Tuttavia il istest è più veloce e la convenzione Pythonic deve essere utilizzata foo is None.

Se si sta facendo un po 'di introspezione o pasticciare in giro con la raccolta dei rifiuti o di verificare se la stringa su misura internato gadget funziona o simili, allora probabilmente avete un caso d'uso per fooè bar.

Vero e falso sono anche (ora) singleton, ma non esiste alcun caso d' foo == Trueuso e nessun caso d'uso per foo is True.


2

Molti di loro hanno già risposto al punto. Proprio come una nota aggiuntiva (basata sulla mia comprensione e sperimentazione ma non da una fonte documentata), la dichiarazione

== se gli oggetti a cui fanno riferimento le variabili sono uguali

da sopra le risposte dovrebbero essere lette come

== se gli oggetti a cui fanno riferimento le variabili sono uguali e gli oggetti appartenenti allo stesso tipo / classe

. Sono arrivato a questa conclusione sulla base del test seguente:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

Qui il contenuto dell'elenco e della tupla sono uguali ma il tipo / classe sono diversi.


2

Python differenza tra is e uguale (==)

L'operatore is può sembrare uguale all'operatore di uguaglianza ma non sono uguali.

Is verifica se entrambe le variabili puntano allo stesso oggetto mentre il segno == verifica se i valori per le due variabili sono uguali.

Quindi se l'operatore is restituisce True, l'uguaglianza è sicuramente True, ma il contrario può essere o meno True.

Ecco un esempio per dimostrare la somiglianza e la differenza.

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.

1
Utilizza solo le virgolette per il testo che hai citato da un'altra fonte, a quel punto devi includere l'attribuzione (vedi stackoverflow.com/help/referencing ). Se questo è il tuo testo, rimuovi le virgolette.
Martijn Pieters

0

Dato che le altre persone in questo post rispondono in dettaglio alla domanda, vorrei sottolineare principalmente il confronto tra ise == per le stringhe che possono dare risultati diversi e esorto i programmatori a usarle con attenzione.

Per il confronto delle stringhe, assicurarsi di utilizzare ==invece di is:

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

Su:

str is hello
str == hello

Ma nell'esempio che segue ==e issi ottengono risultati diversi:

str = 'hello sam'
    if (str is 'hello sam'):
        print ('str is hello sam')
    if (str == 'hello sam'):
        print ('str == hello sam')

Su:

str == hello sam

Conclusione:

Usare isattentamente per confrontare tra le stringhe


perché "è" "funziona così per stringhe con spazi?
Akash Gupta,

Secondo le risposte precedenti: sembra che Python esegua la memorizzazione nella cache su interi e stringhe di piccole dimensioni, il che significa che utilizza lo stesso riferimento oggetto per le occorrenze di stringa "ciao" in questa istantanea del codice, mentre non ha preformato la memorizzazione nella cache per "ciao sam" come è relativamente più grande di 'hello' (cioè gestisce diversi riferimenti della stringa 'hello sam', ed è per questo che l'operatore 'is' restituisce false nell'esempio successivo) Per favore correggimi se sbaglio
Rida Shamasneh
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.