2009-04-15 9 views
46

È una cattiva pratica utilizzare il seguente formato quando my_var può essere Nessuno?È sicuro affidarsi all'ordine di valutazione delle condizioni nelle istruzioni if?

if my_var and 'something' in my_var: 
    #do something 

Il problema è che 'something' in my_var lancerà una TypeError se my_var è Nessuno.

O devo usare:

if my_var: 
    if 'something' in my_var: 
     #do something 

o

try: 
    if 'something' in my_var: 
     #do something 
except TypeError: 
    pass 

di riformulare la domanda, che di quanto sopra è la migliore pratica in Python (se del caso)?

Le alternative sono benvenute!

risposta

64

È sicuro dipendere dall'ordine dei condizionali (Python reference here), in particolare a causa del problema che si fa notare: è molto utile essere in grado di eseguire una valutazione di cortocircuito che potrebbe causare problemi in una serie di condizioni.

Questa sorta di codice si apre nella maggior parte delle lingue:

IF exists(variable) AND variable.doSomething() 
    THEN ... 
+2

Quando vedo il codice come il secondo, presumo che il codificatore non abbia capito come funziona la valutazione di cortocircuito. – Dana

+1

-1: Nessuna citazione dalla documentazione: http://docs.python.org/library/stdtypes.html#boolean-operations-and-or-not –

+0

@cfi: Poiché posso modificare il mio voto dopo che la risposta è cambiata, Non sono chiaro su quale sia il problema. –

1

è perfettamente sicuro e lo faccio tutto il tempo.

1

Vorrei andare con la prova/eccetto, ma dipende da cosa sai della variabile.

Se ci si aspetta che la variabile esista la maggior parte del tempo, quindi un tentativo/eccetto è meno operazioni. Se si prevede che la variabile sia None per la maggior parte del tempo, allora un'istruzione IF avrà meno operazioni.

+0

perché (leggibilità, prestazioni, ecc.)? – tgray

+0

ho aggiornato la risposta –

27

Si è sicuro, è esplicitamente e molto chiaramente definito nel riferimento lingua:

L'espressione x and y prima valuta x; se x è false, il suo valore è restituito; altrimenti, viene valutato e viene restituito il valore risultante.

L'espressione x or y prima valuta x; se x è true, il suo valore è restituito; altrimenti, viene valutato e viene restituito il valore risultante.

+1

Debole: non è "sicuro" - è assolutamente necessario dipendere dall'ordine. –

1

Non è così semplice. Come un C# tizio Sono molto abituato a fare qualcosa di simile:

if(x != null && ! string.isnullorempty(x.Name)) 
{ 
    //do something 
} 

È possibile che questo funziona alla grande e viene valutata come previsto. Tuttavia in VB.Net seguito avrebbe prodotto un risultato che non ti aspetti:

If Not x Is Nothing **And** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

È possibile che questo genererà un'eccezione.La sintassi corretta dovrebbe essere

If Not x Is Nothing **AndAlso** Not String.IsNullOrEmpty(x.Name) Then 

    'do something 

End If 

Nota la differenza molto sottile. Questo mi ha confuso per circa 10 minuti (troppo a lungo) ed è il motivo per cui C# (e altri) tizi devono fare molta attenzione quando codificano in altre lingue.

2

io possa essere di essere un po 'pedanti qui, ma direi che la risposta migliore è

if my_var is not None and 'something' in my_var: 
    #do something 

La differenza è il controllo esplicito per None, piuttosto che la conversione implicita di my_var-True o False.

Mentre sono sicuro che nel tuo caso la distinzione non è importante, nel caso più generale sarebbe del tutto possibile per la variabile di non essere None ma ancora valutare a False, ad esempio un valore intero di 0 o una lista vuota.

Quindi, contrariamente alla maggior parte delle affermazioni degli altri utenti che è sicuro, direi che è sicuro finché sei esplicito. Se non siete convinti quindi prendere in considerazione questa classe molto artificiosa:

class Contrived(object): 
    def __contains__(self, s): 
     return True 
    def __nonzero__(self): 
     return False 

my_var = Contrived() 
if 'something' in my_var: 
    print "Yes the condition is true" 
if my_var and 'something' in my_var: 
    print "But this statement won't get reached." 
if my_var is not None and 'something' in my_var: 
    print "Whereas this one will." 

Sì, lo so che non è un esempio realistico, ma le variazioni accadono nel codice vero e proprio, soprattutto quando None viene utilizzato per indicare un argomento di funzione di default.

+0

sicuramente, se si dispone di una lista vuota o di qualsiasi contenitore, del resto, l'operazione 'in' non ha senso. Penso che OP abbia esattamente ragione. mentre è possibile costruire qualsiasi cosa per dimostrare il proprio punto, non credo che un codice decente debba spararsi ai piedi. – SilentGhost

+1

Sì, è un esempio forzato, ma il mio punto principale è che è facile entrare nella cattiva abitudine di dire "se var" quando si intende veramente "se var non è None". Una volta che hai preso quell'abitudine ti può facilmente mordere, in particolare con argomenti predefiniti. –

+0

Penso che sia abbastanza chiaro che l'intenzione di OP era di dire "se var" e questo è quello che ha fatto. – SilentGhost