In un commento su questa domanda , ho visto una dichiarazione che raccomandava di usare
result is not None
vs
result != None
Mi chiedevo quale fosse la differenza e perché uno potrebbe essere raccomandato rispetto all'altro?
In un commento su questa domanda , ho visto una dichiarazione che raccomandava di usare
result is not None
vs
result != None
Mi chiedevo quale fosse la differenza e perché uno potrebbe essere raccomandato rispetto all'altro?
Risposte:
==
è un test di uguaglianza . Verifica se il lato destro e il lato sinistro sono oggetti uguali (secondo i metodi __eq__
o __cmp__
).
is
è un test di identità . Verifica se il lato destro e il lato sinistro sono lo stesso oggetto. Non viene eseguito alcun metodo, gli oggetti non possono influenzare l' is
operazione.
Usi is
(e is not
) per i singleton, ad esempio None
, dove non ti importa degli oggetti che potrebbero voler fingere di essere None
o dove vuoi proteggere dagli oggetti che si rompono quando vengono confrontati None
.
None
ha pochi metodi e quasi nessun attributo. Se il __eq__
test prevede un metodo o un attributo, potrebbe interrompersi. def __eq__( self, other ): return self.size == other.size
. Ad esempio, si romperà se other
succede None
.
is
è come quello di Java ==
. Python ==
è come Java .equals()
. Naturalmente questo aiuta solo se conosci Java.
is
è simile ===
(molto uguale) e viceversa is not
è simile !==
(non esattamente uguale).
is not
un singolo operatore o sta semplicemente negando il risultato di is
come internamente not foo is bar
?
Prima di tutto, lasciami esaminare alcuni termini. Se desideri solo rispondere alla tua domanda, scorri verso il basso fino a "Rispondi alla tua domanda".
Identità oggetto : quando si crea un oggetto, è possibile assegnarlo a una variabile. È quindi possibile anche assegnarlo a un'altra variabile. E un altro.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
In questo caso, cancel
, close
, e dismiss
si riferiscono tutti allo stesso oggetto in memoria. Hai creato solo un Button
oggetto e tutte e tre le variabili si riferiscono a questo oggetto. Diciamo che cancel
, close
e dismiss
tutti si riferiscono a oggetti identici ; cioè, si riferiscono a un singolo oggetto.
Uguaglianza degli oggetti : quando si confrontano due oggetti, di solito non ti interessa che si riferisca esattamente allo stesso oggetto in memoria. Con l'uguaglianza degli oggetti, è possibile definire le proprie regole per il confronto tra due oggetti. Quando scrivi if a == b:
, essenzialmente dici if a.__eq__(b):
. Ciò consente di definire un __eq__
metodo in a
modo da poter utilizzare la propria logica di confronto.
Motivazione: Due oggetti hanno gli stessi dati esatti, ma non sono identici. (Non sono lo stesso oggetto in memoria.) Esempio: stringhe
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
Nota: utilizzo qui stringhe unicode perché Python è abbastanza intelligente da riutilizzare stringhe regolari senza crearne di nuove in memoria.
Qui, ho due stringhe unicode a
e b
. Hanno lo stesso contenuto esatto, ma non sono lo stesso oggetto in memoria. Tuttavia, quando li confrontiamo, vogliamo che siano uguali. Quello che sta succedendo qui è che l'oggetto unicode ha implementato il __eq__
metodo.
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
Nota: __eq__
on unicode
è sicuramente implementato in modo più efficiente di così.
Motivazione: Due oggetti hanno dati diversi, ma sono considerati lo stesso oggetto se alcuni dati chiave sono uguali. Esempio: la maggior parte dei tipi di dati del modello
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
Qui, ho due monitor Dell a
e b
. Hanno la stessa marca e modello. Tuttavia, non hanno gli stessi dati né lo stesso oggetto in memoria. Tuttavia, quando li confrontiamo, vogliamo che siano uguali. Quello che sta succedendo qui è che l'oggetto Monitor ha implementato il __eq__
metodo.
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
In confronto a None
, utilizzare sempre is not
. Nessuno è un singleton in Python - ne esiste solo un'istanza in memoria.
Confrontando l' identità , questo può essere eseguito molto rapidamente. Python verifica se l'oggetto a cui ti riferisci ha lo stesso indirizzo di memoria dell'oggetto Nessuno globale, un confronto molto, molto veloce di due numeri.
Confrontando l' uguaglianza , Python deve cercare se il tuo oggetto ha un __eq__
metodo. In caso contrario, esamina ogni superclasse alla ricerca di un __eq__
metodo. Se ne trova uno, Python lo chiama. Ciò è particolarmente negativo se il __eq__
metodo è lento e non ritorna immediatamente quando nota che l'altro oggetto è None
.
Non hai implementato __eq__
? Quindi Python probabilmente troverà il __eq__
metodo attivo object
e lo userà invece, il che controlla comunque l'identità dell'oggetto.
Quando confronterai la maggior parte delle altre cose in Python, utilizzerai !=
.
Considera quanto segue:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
None
è un singleton, quindi il confronto di identità funzionerà sempre, mentre un oggetto può falsificare il confronto di uguaglianza tramite .__eq__()
.
None
, ma un comportamento scorretto in merito None
potrebbe verificarsi come effetto collaterale dell'implementazione dell'uguaglianza contro altri tipi. Non sono tante implicazioni per la sicurezza ma solo implicazioni sulla correttezza.
>>> () è () Vero >>> 1 è 1 Vero >>> (1,) == (1,) Vero >>> (1,) è (1,) falso >>> a = (1,) >>> b = a >>> a è b Vero
Alcuni oggetti sono singoli, e quindi is
con essi è equivalente ==
. La maggior parte no.
()
e 1
non sono intrinsecamente singoli.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) e le tuple vuote sono singoli. In effetti non è documentato né garantito, ma è improbabile che cambi.