Ho visto diversi esempi di codice come questo:
if not someobj:
#do something
Ma mi chiedo perché non farlo:
if someobj == None:
#do something
C'è qualche differenza? Uno ha un vantaggio rispetto all'altro?
X != None?
Ho visto diversi esempi di codice come questo:
if not someobj:
#do something
Ma mi chiedo perché non farlo:
if someobj == None:
#do something
C'è qualche differenza? Uno ha un vantaggio rispetto all'altro?
X != None?
Risposte:
Nel primo test, Python prova a convertire l'oggetto in un boolvalore se non lo è già. In parole povere, chiediamo l'oggetto: hai senso o no? Questo viene fatto utilizzando il seguente algoritmo:
Se l'oggetto ha un __nonzero__metodo speciale (come i built-in numerici inte float), chiama questo metodo. Deve restituire un boolvalore che viene quindi utilizzato direttamente o un intvalore considerato Falsese uguale a zero.
Altrimenti, se l'oggetto ha un __len__metodo speciale (come fanno container built-in, list, dict, set, tuple, ...), chiama questo metodo, si considera un contenitore Falsese vuota (lunghezza è zero).
Altrimenti, l'oggetto viene considerato a Truemeno che non sia Nonenel qual caso, viene considerato False.
Nel secondo test, l'oggetto viene confrontato per uguaglianza None. Qui, stiamo chiedendo all'oggetto: "Sei uguale a questo altro valore?" Questo viene fatto utilizzando il seguente algoritmo:
Se l'oggetto ha un __eq__metodo, viene chiamato e il valore restituito viene quindi convertito in un boolvalore e utilizzato per determinare il risultato di if.
Altrimenti, se l'oggetto ha un __cmp__metodo, viene chiamato. Questa funzione deve restituire intun'indicazione dell'ordine dei due oggetti ( -1if self < other, 0if self == other, +1if self > other).
Altrimenti, l'oggetto viene confrontato per identità (cioè sono riferimento allo stesso oggetto, come può essere testato isdall'operatore).
È possibile eseguire un altro test utilizzando l' isoperatore. Vorremmo chiedere all'oggetto: "Sei questo particolare oggetto?"
In generale, consiglierei di utilizzare il primo test con valori non numerici, di utilizzare il test per l'uguaglianza quando si desidera confrontare oggetti della stessa natura (due stringhe, due numeri, ...) e verificare l'identità solo quando usando valori sentinella ( Nonesignificato non inizializzato per un campo membro per esempio, o quando si usano getattri __getitem__metodi o ).
Riassumendo, abbiamo:
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
Queste sono in realtà entrambe cattive pratiche. C'era una volta, era considerato OK trattare casualmente None e False come simili. Tuttavia, dal momento che Python 2.2 questa non è la migliore politica.
In primo luogo, quando si fa un if xo if not xtipo di test, Python deve convertire implicitamente xa booleani. Le regole per la boolfunzione descrivono una zattera di cose false; tutto il resto è vero. Se il valore di x non era correttamente booleano all'inizio, questa conversione implicita non è davvero il modo più chiaro per dire le cose.
Prima di Python 2.2 non esisteva la funzione bool, quindi era ancora meno chiaro.
Secondo, non dovresti davvero provare con == None. Dovresti usare is Nonee is not None.
Vedi PEP 8, Guida allo stile per Python Code .
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. Also, beware of writing "if x" when you really mean "if x is not None" -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
Quanti sono i singoli? Cinque: None, True, False, NotImplementede Ellipsis. Dal momento che è molto improbabile che tu usi NotImplementedo Ellipsis, e non lo diresti mai if x is True(perché semplicemente if xè molto più chiaro), lo testerai sempre e solo None.
Perché Nonenon è l'unica cosa considerata falsa.
if not False:
print "False is false."
if not 0:
print "0 is false."
if not []:
print "An empty list is false."
if not ():
print "An empty tuple is false."
if not {}:
print "An empty dict is false."
if not "":
print "An empty string is false."
False, 0, (), [], {}E ""sono tutte diverse None, in modo che le due frammenti di codice sono non equivalenti.
Inoltre, considera quanto segue:
>>> False == 0
True
>>> False == ()
False
if object:non è un controllo di uguaglianza. 0, (), [], None, {}, Ecc sono tutte diverse le une dalle altre, ma tutte valutare False.
Questa è la "magia" dietro espressioni di corto circuito come:
foo = bar and spam or eggs
che è una scorciatoia per:
if bar:
foo = spam
else:
foo = eggs
anche se dovresti davvero scrivere:
foo = spam if bar else egg
PEP 8 - Guida allo stile per il codice Python raccomanda di utilizzo è o non è se si sta testando per None-ness
- Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators.
D'altra parte, se si sta eseguendo il test per un valore superiore a Assente, è necessario utilizzare l'operatore booleano.
Se chiedi
if not spam:
print "Sorry. No SPAM."
viene chiamato il metodo __nonzero__ di spam . Dal manuale di Python:
__nonzero__ ( self ) Chiamato per implementare il test del valore di verità e l'operazione integrata bool (); dovrebbero restituire False o True o i loro equivalenti interi 0 o 1. Quando questo metodo non è definito, viene chiamato __len __ (), se definito (vedere di seguito). Se una classe non definisce né __len __ () né __nonzero __ (), tutte le sue istanze sono considerate vere.
Se chiedi
if spam == None:
print "Sorry. No SPAM here either."
il metodo __eq__ di spam viene chiamato con l'argomento Nessuno .
Per maggiori informazioni sulle possibilità di personalizzazione, dai un'occhiata alla documentazione di Python su https://docs.python.org/reference/datamodel.html#basic-customization
Questi due confronti hanno scopi diversi. Il primo controlla il valore booleano di qualcosa, il secondo controlla l'identità con valore None.
La risposta è, dipende".
Uso il primo esempio se considero 0, "", [] e False (elenco non esaustivo) equivalenti a None in questo contesto.
Personalmente, ho scelto un approccio coerente tra le lingue: lo faccio if (var)(o equivalente) solo se var è dichiarato booleano (o definito come tale, in C non abbiamo un tipo specifico). Ho anche prefisso queste variabili con un b(quindi sarebbe bVareffettivamente) per essere sicuro che non userò accidentalmente un altro tipo qui.
Non mi piace molto il cast implicito in booleano, ancor meno quando ci sono numerose regole complesse.
Certo, le persone non saranno d'accordo. Alcuni vanno oltre, vedo if (bVar == true)nel codice Java sul mio lavoro (troppo ridondante per i miei gusti!), Altri amano una sintassi troppo compatta, andando while (line = getNextLine())(troppo ambiguo per me).