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' isoperazione.
Usi is(e is not) per i singleton, ad esempio None, dove non ti importa degli oggetti che potrebbero voler fingere di essere Noneo dove vuoi proteggere dagli oggetti che si rompono quando vengono confrontati None.
Noneha 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 othersuccede 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 notun singolo operatore o sta semplicemente negando il risultato di iscome 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 dismisssi riferiscono tutti allo stesso oggetto in memoria. Hai creato solo un Buttonoggetto e tutte e tre le variabili si riferiscono a questo oggetto. Diciamo che cancel, closee dismisstutti 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 amodo 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 ae 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 ae 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 objecte 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 Nonepotrebbe 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 iscon essi è equivalente ==. La maggior parte no.
()e 1non sono intrinsecamente singoli.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS) e le tuple vuote sono singoli. In effetti non è documentato né garantito, ma è improbabile che cambi.