Wie soll ich in Python testen, ob eine Variable None, True oder False ist?

146

Ich habe eine Funktion, die eines von drei Dingen zurückgeben kann:

  • Erfolg ( True)
  • Fehler ( False)
  • Fehler beim Lesen / Parsen von Stream ( None)

Meine Frage ist, ob ich nicht gegen Trueoder testen soll False, wie ich das Ergebnis sehen soll. Unten ist, wie ich es gerade mache:

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"

Ist es wirklich so einfach wie das Entfernen des == TrueTeils oder sollte ich einen Tri-Bool-Datentyp hinzufügen? Ich möchte nicht, dass die simulateFunktion eine Ausnahme auslöst, da das äußere Programm nur einen Fehler protokollieren und fortfahren soll.

James Brooks
quelle
Sie stellen die falsche Frage; Sie sollten um Hilfe bei der Definition Ihres Ergebnisses bitten ... Was ist der Unterschied, den Sie zwischen "Fehler" und "Fehleranalyse-Stream" wahrnehmen, was bedeuten sie, was sind die Konsequenzen, welche Maßnahmen möchte der Anrufer wahrscheinlich ergreifen? in jedem Fall (bestanden, nicht bestanden, Fehler analysieren)?
John Machin
Ich simuliere ein Stromnetz. Wenn Menschen Strom an ihre Häuser verlieren, ist dies ein Fehler. Wenn ich die Simulationsdatei nicht lesen kann, ist das ein ganz anderer Fehler.
James Brooks
2
Innerhalb der simulateFunktion fange ich alle Ausnahmen ab; Ich möchte nicht, dass irgendetwas, das im Simulator passiert, den Rest des Programms stoppt (und das nächste Element verarbeitet). Aber die Antworten bringen mich dazu, meine Meinung zu ändern.
James Brooks
1
@ James Brooks: Richtig. Darum geht es bei Try / außer Processing. Wenn Sie simulateDinge haben, die es fangen und erneut versuchen kann, ist das gut. Aber wenn es "fehlschlägt", sollte es nicht zurückkehren None. Es sollte nur eine Ausnahme zu dem Skript auslösen, das es aufgerufen hat. So oder so simulateist es geschafft. Die Rückgabe Noneist nicht so hilfreich wie das Auslösen einer richtigen Ausnahme - oder das Weitergeben einer Ausnahme simulatein das aufrufende Skript zur Behandlung.
S.Lott
1
@ James, benutze except Exception:stattdessen. Dies fängt alle "echten" Fehler zusammen mit Warningund ab StopIteration. Es erlaubt KeyboardInterruptund SystemExitdurch. Wenn Sie diese wirklich fangen möchten, ist es wahrscheinlich am besten, einen anderen äußeren Versuch / eine andere Struktur zu verwenden, die Ihre Absicht klar dokumentiert, da dies keine "Fehler" sind. (Aber ich habe "fast nie" gesagt ... vielleicht möchten Sie in Ihrem Fall wirklich alles ergreifen und sogar Strg-C verhindern oder das sys.exit()Verlassen beenden usw.)
Peter Hansen

Antworten:

119

Fürchte die Ausnahme nicht! Wenn Sie Ihr Programm nur protokollieren und fortfahren, ist dies so einfach wie:

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

Und jetzt können Sie mit der Simulationsmethode eine viel umfangreichere Art der Benachrichtigung darüber erhalten, was genau schief gelaufen ist, falls Sie feststellen, dass Fehler / kein Fehler nicht informativ genug sind.

PaulMcG
quelle
Einverstanden. Viel pythonischer als die offensichtlich populärere Lösung oben (die zu sehr nach C-Code riecht).
Brandon
7
@Brandon Nicht vereinbart. Dieser Code ist länger und, schlimmer noch, weniger lesbar als die obige Lösung (oder die verbesserte Version unten): mehr Einrückungen, mehr unterschiedliche Aussagen - raten Sie mal, warum letzterer populärer ist, wie Sie sagen ... ;-) Warum versuchen zu sein 'Pythonic', wenn das zu unangenehmerem Code führt ...?
Rolf Bartstra
Drucken Sie jetzt den Traceback anstelle von "Fehleranalyse-Stream" und Sie haben meine Stimme erhalten.
CivFan
Ok, du hast trotzdem meine Stimme bekommen, aber ich wollte so etwas drucken traceback.format_exc() . Siehe diese SO-Antwort.
CivFan
10
Viele Leute werden auf diese Seite kommen und nach der Antwort auf die Titelfrage suchen. Für die meisten von uns "Fürchte die Ausnahme nicht!" hat nichts mit unserer Situation zu tun. Wir müssen nur auf Wahr, Falsch und Keine testen. Obwohl Ihre vorgeschlagene Alternative in einigen Fällen gültig ist, ist es meiner Meinung nach am besten, auch eine Antwort auf die gestellte Frage beizufügen.
Vastlysuperiorman
161
if result is None:
    print "error parsing stream"
elif result:
    print "result pass"
else:
    print "result fail"

halte es einfach und explizit. Sie können natürlich ein Wörterbuch vordefinieren.

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

Wenn Sie vorhaben, Ihre simulateFunktion so zu ändern, dass sie mehr Rückkehrcodes enthält, kann die Pflege dieses Codes zu einem Problem werden.

Dies simulatekönnte auch eine Ausnahme für den Parsing-Fehler auslösen. In diesem Fall würden Sie ihn entweder hier abfangen oder eine Stufe höher verbreiten lassen, und das Druckbit würde auf eine einzeilige if-else-Anweisung reduziert.

SilentGhost
quelle
1
Letzteres ist eine Art expliziter Test gegen Richtig oder Falsch, nicht wahr?
Peter Eisentraut
1
Natürlich, aber da ich weiß, dass dies nur mögliche Rückgabewerte sind, denke ich nicht, dass dies ein Problem ist.
SilentGhost
und es scheint auch ein bisschen schneller zu sein
SilentGhost
a = 'foo' wenn a: print 'its true' a ist nicht wirklich WAHR, es ist einfach keine
wesm
17

Niemals, niemals, niemals sagen

if something == True:

Noch nie. Es ist verrückt, da Sie redundant wiederholen, was redundant als redundante Bedingungsregel für eine if-Anweisung angegeben ist.

Schlimmer noch, niemals, niemals, niemals

if something == False:

Du hast not. Fühlen Sie sich frei, es zu benutzen.

Schließlich ist das Tun a == Noneineffizient. Tu es a is None. Noneist ein spezielles Singleton-Objekt, es kann nur eines geben. Überprüfen Sie einfach, ob Sie dieses Objekt haben.

S.Lott
quelle
3
Das Testen auf Gleichheit mit Trueist nicht überflüssig (obwohl ich damit einverstanden bin, dass es nicht sinnvoll ist). Es könnte sich um eine __eq__oder eine andere spezielle Methode handeln, die praktisch alles kann.
Scott Griffiths
5
@ Scott Griffiths: Guter Punkt. Das ist ein wirklich und zutiefst schreckliches Szenario. Wenn dies tatsächlich der Fall ist, verletzt das Programm unsere grundlegenden Erwartungen auf eine Weise, die es zu etwas macht, das ohne solche schwarze Magie einfach gelöscht und von Grund auf neu geschrieben werden muss.
S.Lott
78
'Nie nie nie' ...? Es gibt jedoch Fälle, if something == Truedie ein anderes Ergebnis liefern als if somethingz. B. für nicht-boolesche something. 2==Trueergibt false, während 2true bewertet wird; None==Falseist falsch aber not Noneist wahr!
Rolf Bartstra
9
-1 Diese Antwort ist irreführend und völlig falsch, da das, was @Rolf Bartstra sagt, wahr ist. Obwohl in diesem Fall, was Sie sagen, kann angewendet werden.
HelloGoodbye
3
-1. Da jeder Wert ungleich Null oder nicht leer oder ungleich Null fürsomething Rückgabe Trueauf bool(something). In diesem Fall , wenn Sie überprüfen möchten , ob somethingeinen Wert von TruezB bool. Dann musst du if something == TrueIMO machen.
Samarth Shah
2

Ich möchte betonen, dass, selbst wenn es Situationen gibt, in denen dies if expr :nicht ausreicht, weil man sicherstellen möchte, dass expres Truenicht nur anders ist als 0/ None/ was auch immer, ises aus == dem gleichen Grund vorzuziehen ist, den S.Lott zur Vermeidung erwähnt hat== None .

Es ist in der Tat etwas effizienter und, menschlich lesbar, besser lesbar.

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)
Thrastylon
quelle
1
Sie können einen Benchmark nicht einmal ausführen und sagen, dass einer effizienter ist als der andere (auch wenn dies möglicherweise der Fall ist). Führen Sie es viele Male (10.000) aus, um zu sehen, wie es sich im Durchschnitt verhält. \
user1767754
1

Ich glaube, dass das Auslösen einer Ausnahme eine bessere Idee für Ihre Situation ist. Eine Alternative ist die Simulationsmethode, um ein Tupel zurückzugeben. Der erste Punkt ist der Status und der zweite das Ergebnis:

result = simulate(open("myfile"))
if not result[0]:
  print "error parsing stream"
else:
  ret= result[1]
kgiannakakis
quelle
1
Das Zurückgeben eines Tupels
passt
2
Ihr Code macht jedoch wenig Sinn. Wenn er Falsezurückgegeben wird, wird er gedruckt 'error parsing stream'.
SilentGhost
Die Simulationsmethode sollte (False, "irgendetwas überhaupt") oder (True, ret) zurückgeben, wobei ret entweder False oder True ist.
kgiannakakis
2
Nun