C'è qualche differenza tra "foo is None" e "foo == None"?


217

C'è qualche differenza tra:

if foo is None: pass

e

if foo == None: pass

La convenzione che ho visto nella maggior parte del codice Python (e nel codice che scrivo io stesso) è la prima, ma di recente mi sono imbattuto in codice che utilizza la seconda. Nessuna è un'istanza (e l'unica istanza, IIRC) di NoneType, quindi non dovrebbe importare, giusto? Ci sono circostanze in cui potrebbe?

Risposte:


253

isrestituisce sempre Truese confronta la stessa istanza di oggetto

Considerando che alla ==fine è determinato dal __eq__()metodo

vale a dire


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False

51
Puoi aggiungere che None è un singleton, quindi "None is None" è sempre True.
e-soddisfa il

43
E potresti voler aggiungere che l' isoperatore non può essere personalizzato (sovraccaricato da una classe definita dall'utente).
martineau,

@study Il metodo __eq__(self)è uno speciale metodo incorporato che determina come ==viene gestito quando utilizzato su un oggetto Python. Qui lo abbiamo sovrascritto in modo che quando ==viene usato su oggetti di tipo Fooritorni sempre vero. Non esiste un metodo equivalente per l' isoperatore e quindi il comportamento di isnon può essere modificato allo stesso modo.
Brendan,

È perché la definizione della classe foo non ha un costruttore, cioè la funzione init ?
studia il

49

Potresti voler leggere questa identità e l'equivalenza di questo oggetto .

L'istruzione 'is' viene utilizzata per l'identità dell'oggetto, controlla se gli oggetti si riferiscono alla stessa istanza (stesso indirizzo in memoria).

E l'istruzione '==' si riferisce all'uguaglianza (stesso valore).


Hmmm, penso che il tuo link sia cambiato, a meno che tu non sia interessato a come chiamare funzioni esterne da Python
Pat

Ci ho appena provato a=1;b=1;print(a is b) # True. Qualche idea sul perché si a is brivelino veri anche se sembrano essere 2 oggetti diversi (indirizzo diverso in memoria)?
Johnny Chiu,

24

Un avvertimento:

if foo:
  # do something

Non è esattamente lo stesso di:

if x is not None:
  # do something

Il primo è un test di valore booleano e può essere valutato come falso in contesti diversi. Ci sono un certo numero di cose che rappresentano false nei test di valori booleani, ad esempio contenitori vuoti, valori booleani. Nessuno valuta anche falso in questa situazione, ma lo fanno anche altre cose.


12

(ob1 is ob2) uguale a (id(ob1) == id(ob2))


6
... ma (ob is ob2) è MOLTO più veloce. Timeit dice "(a is b)" è 0,0365 usec per loop e "(id (a) == id (b))" è 0,153 usec per loop. 4.2x più veloce!
AKX,

4
la isversione non ha bisogno di alcuna chiamata di funzione e nessuna ricerca dell'attributo interprete python; l'interprete può rispondere immediatamente se ob1 è, in effetti, ob2.
u0b34a0f6ae,

17
No non lo fa. {} is {}è falso e id({}) == id({})può essere (ed è in CPython) vero. Vedi stackoverflow.com/questions/3877230
Piotr Dobrogost,

12

Il motivo foo is Noneè il modo preferito è che potresti gestire un oggetto che definisce il proprio __eq__e che definisce l'oggetto uguale a Nessuno. Quindi, usa sempre foo is Nonese hai bisogno di vedere se è infatti None.


8

Non c'è differenza perché gli oggetti identici saranno ovviamente uguali. Tuttavia, PEP 8 afferma chiaramente che è necessario utilizzare is:

Il confronto con singoli come nessuno dovrebbe sempre essere fatto con o non è, mai operatori di uguaglianza.


7

istest per l'identità, non per l' uguaglianza. Per la tua affermazione foo is none, Python confronta semplicemente l'indirizzo di memoria degli oggetti. Significa che stai ponendo la domanda "Ho due nomi per lo stesso oggetto?"

==dall'altro lato verifica l'uguaglianza determinata dal __eq__()metodo. Non importa dell'identità.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Noneè un operatore singleton. Quindi None is Noneè sempre vero.

In [101]: None is None
Out[101]: True

5

Per None non dovrebbe esserci differenza tra uguaglianza (==) e identità (is). NoneType probabilmente restituisce identità per uguaglianza. Poiché None è l'unica istanza che puoi fare di NoneType (penso che sia vero), le due operazioni sono le stesse. Nel caso di altri tipi questo non è sempre il caso. Per esempio:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Ciò stamperebbe "Uguale" poiché gli elenchi hanno un'operazione di confronto che non è la restituzione predefinita dell'identità.


5

@ Jason :

Consiglio di usare qualcosa di più sulla falsariga di

if foo:
    #foo isn't None
else:
    #foo is None

Non mi piace usare "if foo:" a meno che foo non rappresenti davvero un valore booleano (ovvero 0 o 1). Se foo è una stringa o un oggetto o qualcos'altro, "if foo:" potrebbe funzionare, ma a me sembra una scorciatoia pigra. Se stai controllando per vedere se x è Nessuno, dì "se x è Nessuno:".


Controllare le stringhe / elenchi vuoti con "if var" è il modo preferito. La conversione booleana è ben definita ed è anche meno codice che funziona meglio. Nessun motivo per fare "if len (mylist) == 0" per esempio.
truppo,

Sbagliato. Supponiamo che foo = "". Quindi if foorestituirà false e il commento #foo is Noneè errato.
Blokeley,

Nota per i votanti: la mia risposta sta citando una risposta che è stata successivamente cancellata e in disaccordo con essa. Se non ti piace il codice nella mia risposta, devi votare . :-)
Graeme Perrow,

2

Alcuni dettagli in più:

  1. La isclausola controlla effettivamente se i due si objecttrovano nella stessa posizione di memoria o meno. vale a dire se entrambi puntano alla stessa posizione di memoria e hanno la stessa id.

  2. Come conseguenza di 1, isassicura se i due simboli lessicali rappresentati objectabbiano o meno attributi identici (attributi di attributi ...) oppure no

  3. Istanziazione dei tipi primitivi come bool, int, string(con qualche eccezione), NoneTypeavente lo stesso valore sarà sempre nella stessa posizione di memoria.

Per esempio

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

E poiché NoneTypepuò avere solo un'istanza di se stessa nella tabella "look-up" di Python, quindi la prima e la seconda sono più uno stile di programmazione dello sviluppatore che ha scritto il codice (forse per coerenza) piuttosto che avere una ragione logica per scegli uno sopra l'altro.


2
Chiunque legga questo: NON usare some_string is "bar"MAI per confrontare le stringhe MAI. NON C'È UN UNICO MOTIVO ACCETTABILE per farlo e si romperà quando non te lo aspetti. Il fatto che funzioni spesso è semplicemente perché CPython sa che sarebbe stupido creare due oggetti immutabili con lo stesso contenuto. Ma può succedere comunque.
ThiefMaster,

@ThiefMaster ha la tendenza a essere frainteso? Tuttavia, dopo averlo letto di nuovo non sono riuscito a trovarlo (con la menzione di "alcune eccezioni"). La tua affermazione vale solo per le stringhe e non int, giusto?
Bleeding Fingers,

Non proprio, ma dato che hai quell'esempio nella tua risposta, ho pensato che sarebbe stata una buona idea avvisare gli utenti che è una cattiva idea usarlo. Forse aggiungere qualcosa come "# cpython specifico / non garantito" dietro quella linea ...
ThiefMaster

1

La conclusione di John Machin che Noneè un singleton è una conclusione sostenuta da questo codice.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Since Noneè un singleton x == Nonee x is Noneavrebbe lo stesso risultato. Tuttavia, secondo la mia opinione estetica, x == Noneè la cosa migliore.


2
Non sono d'accordo con l'opinione alla fine di questa risposta. Quando si confronta con nessuno in modo esplicito, di solito si intende che l'oggetto in questione è esattamente l' Noneoggetto. In confronto, raramente si vede Nessuno usato in qualsiasi altro contesto se non per essere simile a quello Falsecon altri valori che sono veritieri. In questi casi è più idiomatico fare qualcosa del genereif x: pass
SingleNegationElimination

0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
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.