In Python come devo verificare se una variabile è None, True o False


147

Ho una funzione che può restituire una delle tre cose:

  • successo ( True)
  • fallimento ( False)
  • errore durante la lettura / analisi del flusso ( None)

La mia domanda è, se non dovrei provare contro Trueo False, come dovrei vedere quale sia il risultato. Di seguito è come lo sto facendo attualmente:

result = simulate(open("myfile"))
if result == None:
    print "error parsing stream"
elif result == True: # shouldn't do this
    print "result pass"
else:
    print "result fail"

è davvero semplice come rimuovere la == Trueparte o devo aggiungere un tipo di dati tri-bool. Non voglio che la simulatefunzione generi un'eccezione poiché tutto ciò che voglio che il programma esterno faccia con un errore è registrarlo e continuare.


Stai facendo la domanda sbagliata; dovresti chiedere aiuto per definire il tuo risultato ... qual è la differenza che percepisci tra "errore" e "flusso di analisi degli errori", cosa significano, quali sono le conseguenze, quali azioni è probabile che il chiamante voglia intraprendere in ogni caso (errore passa, fallisci, analizza)?
John Machin,

Sto simulando un sistema di alimentazione elettrica, se le persone perdono energia nelle loro case è un fallimento. Se non riesco a leggere il file di simulazione, questo è un errore di tipo completamente diverso.
James Brooks,

2
All'interno della simulatefunzione colgo tutte le eccezioni; Non voglio che ciò che accade all'interno del simulatore interrompa il resto del programma in esecuzione (e l'elaborazione dell'elemento successivo). Ma le risposte mi stanno facendo cambiare idea.
James Brooks,

1
@James Brooks: Giusto. Questo è ciò che prova / tranne l'elaborazione. Se hai delle simulatecose che può catturare e riprovare, va bene. Ma se "fallisce", non dovrebbe tornare None. Dovrebbe solo sollevare un'eccezione allo script che lo ha chiamato. Ad ogni modo, simulateè fatto. Restituire Nonenon è utile quanto sollevare un'eccezione adeguata o consentire a un'eccezione di propagarsi simulatenello script chiamante per la gestione.
S. Lott,

1
@James, usa except Exception:invece. Questo rileva tutti gli errori "reali", insieme a Warninge StopIteration. Permette KeyboardInterrupte SystemExitattraverso però. Se vuoi davvero catturarli, probabilmente è meglio usare un altro tentativo esterno / tranne o qualche altra struttura che documenta chiaramente le tue intenzioni, dal momento che questi non sono "errori". (Ma ho detto "quasi mai" ... forse nel tuo caso vuoi davvero prendere tutto, e persino impedire a Ctrl-C o sys.exit()di uscire, ecc.)
Peter Hansen,

Risposte:


119

Non temere l'eccezione! Avere il tuo programma basta accedere e continuare è facile come:

try:
    result = simulate(open("myfile"))
except SimulationException as sim_exc:
    print "error parsing stream", sim_exc
else:
    if result:
        print "result pass"
    else:
        print "result fail"

# execution continues from here, regardless of exception or not

E ora puoi avere un tipo di notifica molto più ricco dal metodo di simulazione su cosa è andato esattamente storto, nel caso in cui trovi l'errore / nessun errore non essere abbastanza informativo.


Concordato. Molto più pitonico della soluzione evidentemente più popolare sopra (che puzza troppo di codice C).
Brandon,

7
@Brandon Non concordato. Questo codice è più lungo e, peggio, meno leggibile della soluzione sopra (o della versione migliorata di seguito): più rientri, dichiarazioni più diverse - indovina perché quest'ultimo è più popolare, come dici tu ... ;-) Perché cercare di essere 'Pythonic' se questo porta a un codice più imbarazzante ...?
Rolf Bartstra,

Ora stampa il traceback invece di "errore durante l'analisi del flusso" e hai ottenuto il mio voto.
CivFan,

Ok, hai comunque ottenuto il mio voto, ma intendevo stampare qualcosa del genere traceback.format_exc() . Vedi questa risposta SO.
CivFan,

12
Molte persone verranno su questa pagina in cerca della risposta alla domanda sul titolo. Per la maggior parte di noi "Non temere l'eccezione!" non ha nulla a che fare con la nostra situazione. Dobbiamo solo testare True, False e None. Mentre la tua alternativa suggerita è valida per alcuni casi, penso che sia meglio includere anche una risposta alla domanda come è stata posta.
vastlysuperiorman,

163
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

mantenerlo semplice ed esplicito. Ovviamente puoi pre-definire un dizionario.

messages = {None: 'error', True: 'pass', False: 'fail'}
print messages[result]

Se prevedi di modificare la tua simulatefunzione per includere più codici di ritorno, la manutenzione di questo codice potrebbe diventare un problema.

Ciò simulatepotrebbe anche sollevare un'eccezione sull'errore di analisi, nel qual caso lo cattureresti qui o lasceresti propagare un livello superiore e il bit di stampa verrebbe ridotto a un'istruzione if-else di una riga.


1
Quest'ultimo è una specie di test esplicito contro True o False, non è vero?
Peter Eisentraut,

1
certo, ma sapendo che questi sono solo possibili valori di ritorno, non credo sia un problema.
SilentGhost,

e sembra essere anche un po 'più veloce
SilentGhost

a = 'pippo' se a: stampa 'il suo vero' a non è in realtà VERO, non è proprio nessuno
wesm,

17

Mai, mai, mai dire

if something == True:

Mai. È pazzesco, poiché stai ripetendo in modo ridondante ciò che è ridondante specificato come regola della condizione ridondante per un'istruzione if.

Peggio ancora, mai, mai, mai, mai dire

if something == False:

Hai not. Sentiti libero di usarlo.

Infine, fare a == Noneè inefficiente. Fare a is None. Noneè un oggetto singleton speciale, può essercene solo uno. Controlla per vedere se hai quell'oggetto.


3
Test per l'uguaglianza con Truenon è ridondante (anche se sono d'accordo non è ragionevole). Potrebbe chiamare un __eq__o un altro metodo speciale, che potrebbe fare praticamente qualsiasi cosa.
Scott Griffiths,

5
@Scott Griffiths: buon punto. Questo è uno scenario veramente e profondamente terrificante. In tal caso, il programma viola le nostre aspettative fondamentali in un modo che lo rende qualcosa che deve essere semplicemente cancellato e riscritto da zero senza tale magia nera.
S. Lott,

78
'Mai mai mai' ...? In alcuni casi, tuttavia, si if something == Trueottiene un risultato diverso rispetto if something, ad esempio, ai non booleani something. 2==Trueproduce falso mentre 2valuta vero; None==Falseè falso ma not Noneè vero!
Rolf Bartstra,

9
-1 Questa risposta è fuorviante e completamente errata, poiché ciò che dice @Rolf Bartstra è vero. Anche se in questo caso, ciò che dici può essere applicato.
Ciao addio,

3
-1. Poiché qualsiasi valore diverso da zero o non vuoto o diverso da zero per i somethingritorni Trueattivi bool(something). In tal caso, se si desidera SOLO verificare se somethingha un valore di Trueie bool. Quindi DEVI fare l' if something == TrueIMO.
Samarth Shah,

2

Vorrei sottolineare che, anche se ci sono situazioni in cui if expr :non è sufficiente perché si vuole assicurarsi che exprsia Truee non solo diverso da 0/ None/ qualunque cosa, isè da preferire == per lo stesso motivo per cui S.Lott menzionato per evitare== None .

È davvero leggermente più efficiente e, sulla torta, più leggibile dall'uomo.

In [1]: %timeit (1 == 1) == True
38.1 ns ± 0.116 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [2]: %timeit (1 == 1) is True
33.7 ns ± 0.141 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

1
Non è possibile eseguire un benchmark una volta e dire che uno è più efficiente dell'altro (anche se potrebbe essere). Eseguilo più volte (10.000) per vedere come si comporta in media. \
user1767754

1

Credo che lanciare un'eccezione sia un'idea migliore per la tua situazione. Un'alternativa sarà il metodo di simulazione per restituire una tupla. Il primo elemento sarà lo stato e il secondo il risultato:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]

1
la tupla di ritorno di solito va bene con il disimballaggio di una tupla;)
SilentGhost

2
il tuo codice, tuttavia, non ha molto senso, se Falseviene restituito, verrà stampato 'error parsing stream'.
SilentGhost,

Il metodo di simulazione dovrebbe restituire (False, "niente affatto") o (True, ret) dove ret è False o True.
kgiannakakis,

2
bene, stai ridefinendo i valori di output per adattarli alla tua logica, non è chiaro senza una spiegazione
SilentGhost
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.