Ist es sicher, sich in if-Anweisungen auf die Reihenfolge der Zustandsbewertung zu verlassen?

76

Ist es eine schlechte Praxis, das folgende Format zu verwenden, wenn my_varNone sein kann?

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

Das Problem ist, dass 'something' in my_varein TypeError ausgelöst wird, wenn my_var None ist.

Oder sollte ich verwenden:

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

oder

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

Um die Frage neu zu formulieren: Welche der oben genannten Methoden ist die beste Vorgehensweise in Python (falls vorhanden)?

Alternativen sind willkommen!

tgray
quelle

Antworten:

93

Es ist sicher, sich auf die Reihenfolge der Bedingungen zu verlassen ( Python-Referenz hier ), insbesondere aufgrund des Problems, auf das Sie hinweisen. Es ist sehr nützlich, eine Kurzschlussauswertung durchführen zu können, die Probleme in einer Reihe von Bedingungen verursachen kann.

Diese Art von Code wird in den meisten Sprachen angezeigt:

IF exists(variable) AND variable.doSomething()
    THEN ...
Dan Lew
quelle
3
Wenn ich Code wie den zweiten sehe, gehe ich davon aus, dass der Codierer nicht verstanden hat, wie die Kurzschlussauswertung funktioniert.
Dana
1
-1: Kein Zitat aus der Dokumentation: docs.python.org/library/…
S.Lott
@cfi: Da ich meine Stimme ändern kann, nachdem sich die Antwort geändert hat, bin ich mir nicht sicher, wo das Problem liegt.
S.Lott
@cfi: Mach, was du für andere am wertvollsten hältst. Mein -1 für den Kommentar hat nichts mit meiner tatsächlichen Abstimmung zu tun. Interessanterweise kann man so eine bleibende Bemerkung machen, die nichts mit dem tatsächlichen Wert der Antwort zu tun hat.
S.Lott
1
Für alle, die negativ sind, ist dies eine gültige Frage und nicht für jede Sprache gleich. VB wird beide bewerten, es sei denn, Sie verwenden andalsooderorelse
blindguy
35

Ja, es ist sicher, es ist explizit und sehr klar in der Sprachreferenz definiert:

Der Ausdruck wird x and yzuerst ausgewertet x; Wenn dies der Fall xist false, wird sein Wert zurückgegeben. Andernfalls ywird ausgewertet und der resultierende Wert zurückgegeben.

Der Ausdruck wird x or yzuerst ausgewertet x; Wenn xtrue, wird der Wert zurückgegeben. Andernfalls ywird ausgewertet und der resultierende Wert zurückgegeben.

vartec
quelle
1
Schwach: Es ist nicht "sicher" - es ist unbedingt erforderlich, von der Bestellung abhängig zu sein.
S.Lott
4

Ich mag hier ein wenig pedantisch sein, aber ich würde sagen, die beste Antwort ist

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

Der Unterschied ist die explizite Prüfung auf None, anstatt die implizite Konvertierung von my_varzu Trueoder False.

Während ich in Ihrem Fall sicher bin, dass die Unterscheidung nicht wichtig ist, wäre es im allgemeineren Fall durchaus möglich, dass die Variable nicht, Nonesondern dennoch ausgewertet wird False, beispielsweise ein ganzzahliger Wert von 0oder eine leere Liste.

Entgegen den meisten Behauptungen der anderen Poster, dass es sicher ist, würde ich sagen, dass es sicher ist, solange Sie explizit sind. Wenn Sie nicht überzeugt sind, dann betrachten Sie diese sehr erfundene Klasse:

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."

Ja, ich weiß, dass dies kein realistisches Beispiel ist, aber es kommt zu Abweichungen im realen Code, insbesondere wenn Noneein Standardfunktionsargument angegeben wird.

Scott Griffiths
quelle
Wenn Sie eine leere Liste oder einen Container haben, ist die inOperation sicherlich bedeutungslos. Ich denke, OP hat es genau richtig. Während es möglich ist, irgendetwas zu konstruieren, um seinen Standpunkt zu beweisen, glaube ich nicht, dass sich ein anständiger Code in den Fuß schießen sollte.
SilentGhost
1
Ja, es ist ein erfundenes Beispiel, aber mein Hauptpunkt ist, dass es leicht ist, sich an die schlechte Angewohnheit zu gewöhnen, if var"wenn du wirklich meinst" zu sagen if var is not None. Sobald Sie sich an diese Gewohnheit gewöhnt haben, kann sie Sie leicht beißen, insbesondere bei Standardargumenten.
Scott Griffiths
Ich denke, es ist ziemlich klar, dass OP die Absicht hatte zu sagen, if varund das hat er getan.
SilentGhost
2

Es ist nicht so einfach. Als C # -Kerl bin ich es sehr gewohnt, so etwas zu tun wie:

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

Das obige funktioniert gut und wird wie erwartet bewertet. In VB.Net würde jedoch Folgendes zu einem Ergebnis führen, das Sie NICHT erwartet haben:

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

   'do something

End If

Das Obige wird eine Ausnahme erzeugen. Die richtige Syntax sollte sein

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

   'do something

End If

Beachten Sie den sehr subtilen Unterschied. Dies hat mich ungefähr 10 Minuten lang verwirrt (viel zu lang) und deshalb müssen C # (und andere) Typen beim Codieren in anderen Sprachen sehr vorsichtig sein.

Hans
quelle
1

Ich würde mit dem Versuch / außer gehen, aber es hängt davon ab, was Sie über die Variable wissen.

Wenn Sie erwarten, dass die Variable die meiste Zeit vorhanden ist, ist ein Versuch / eine Ausnahme weniger Operationen. Wenn Sie erwarten, dass die Variable die meiste Zeit Keine ist, enthält eine IF-Anweisung weniger Operationen.

Jason Coon
quelle
0

Es ist absolut sicher und ich mache es die ganze Zeit.

FogleBird
quelle