So beenden Sie eine if-Klausel


104

Welche Methoden gibt es, um eine ifKlausel vorzeitig zu beenden ?

Es gibt Zeiten, in denen ich Code schreibe und eine breakAnweisung in eine ifKlausel einfügen möchte , nur um mich daran zu erinnern, dass diese nur für Schleifen verwendet werden können.

Nehmen wir als Beispiel den folgenden Code:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

Ich kann mir einen Weg vorstellen, dies zu tun: Angenommen, die Exit-Fälle treten in verschachtelten if-Anweisungen auf, verpacken Sie den verbleibenden Code in einen großen else-Block. Beispiel:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

Das Problem dabei ist, dass mehr Exit-Positionen mehr Verschachtelung / eingerückten Code bedeuten.

Alternativ könnte ich meinen Code schreiben, damit die ifKlauseln so klein wie möglich sind und keine Exits erforderlich sind.

Kennt jemand einen guten / besseren Weg, um eine ifKlausel zu beenden?

Wenn es andere else-if- und else-Klauseln gibt, würde das Beenden diese überspringen.


2
Für Ihr zweites Codebeispiel - wissen Sie Bescheid elif?
Craig McQueen

2
"Alternativ könnte ich meinen Code schreiben, damit die if-Klauseln so klein wie möglich sind und keine Exits erforderlich sind." - und dies wäre sicherlich die beste Vorgehensweise. :-)
Michał Marczyk

2
@Craig McQueen: Ja, aber sagen Sie, ich wollte, dass Code zwischen Bedingungsanweisungen ausgeführt wird? ZB if a: #stuff; #stuff_inbetween; if b: #stuff;Der Zwischencode hängt von ab not a, hängt aber nicht davon ab b.
Roman

hallo bitte nicht vergessen elif stackoverflow.com/a/2069680/7045119
kerbrose

Antworten:


99

(Diese Methode funktioniert für ifs, mehrere verschachtelte Schleifen und andere Konstrukte, die Sie nicht breakeinfach verwenden können.)

Wickeln Sie den Code in eine eigene Funktion ein. breakVerwenden Sie stattdessen return.

Beispiel:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

4
Gerne füge ich Ihrer Sammlung von Programmierertricks etwas hinzu. Nach meiner Erfahrung funktioniert dieser Ansatz fast jedes Mal, wenn Sie versucht sind, einen vorwärtsgerichteten Goto zu verwenden. (Und es deutet auf Situationen hin, in denen eine einzelne Funktion zu groß wird, und spricht sie an.)
Drew Dormann,

2
Idealerweise können Sie beides erreichen, aber es gibt Zeiten, in denen Sie guten Code gegen gute Leistung eintauschen müssen. Diese Zeiten sind selten, insbesondere wenn Sie über die Verwendung von Python nachdenken. Mit anderen Worten: Sorgen Sie sich nicht so sehr um den Overhead von Funktionsaufrufen.
Ephemient

17
Es gibt eine alte Anekdote: "Dennis Ritchie förderte die Modularität, indem er allen und jedem sagte, dass Funktionsaufrufe in C wirklich, wirklich billig seien. Alle fingen an, kleine Funktionen zu schreiben und zu modularisieren. Jahre später stellten wir fest, dass Funktionsaufrufe auf dem PDP-11 immer noch teuer waren und VAX-Code verbrachte oft 50% seiner Zeit in der CALLS-Anweisung. Dennis hatte uns angelogen! Aber es war zu spät; wir waren alle süchtig ... "
kurzlebig

1
@ephemient: Das ist lustig, gibt es mehr in der Geschichte? Ich würde gerne das Ganze lesen.
Roman

4
Dieses Zitat stammt aus Kapitel 4 des Buches The Art of Unix Programming (online unter faqs.org/docs/artu ). Sie sollten das Ganze wirklich lesen, wenn Sie es noch nicht getan haben.
Ephemient

55
von goto import goto, label

wenn some_condition:
   ...
   wenn Bedingung_a:
       # etwas tun
       # und verlassen Sie dann den äußeren if-Block
       gehe zum Ende
   ...
   wenn Bedingung_b:
       # etwas tun
       # und verlassen Sie dann den äußeren if-Block
       gehe zum Ende
   # mehr Code hier

Label .end

(Verwenden Sie dies bitte nicht wirklich.)


35
+1 weil das lustig ist. Eine Google-Suche ergab, dass dies ein Aprilscherz-Modul war.
Roman

2
Ich habe auch damit verlinkt. Klicken Sie auf die erste goto.
Ephemient

1
das erinnert mich an Assembler-Code mit allen Arten von Verzweigungen :)
Phunehehe

2
@ Ephemient: Ah, habe den Link nicht bemerkt. Ich dachte, es war Code-Hervorhebung. Aber jetzt, wo ich mir Ihren Code ansehe, sehe ich keine wirklichen Hervorhebungen.
Roman

1
Als PHP goto einführte, wandte ich mich an Python php.net/manual/en/control-structures.goto.php
Marc

25
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break

3
Oh, hey, ich mag diese Idee wirklich. Ich denke, das löst genau meinen ursprünglichen Wunsch. Ich habe jedoch das unangenehme Gefühl, dass dies keine gute Praxis ist (und aus diesem Grund werde ich die derzeit akzeptierte Antwort vorerst beibehalten, da sie einen guten Codierungsstil fördert).
Roman

6
Beachten Sie, dass Sie das Original behalten und das Ganze in a einwickeln können while True:. Stellen Sie einfach sicher, dass Sie breakam Ende eine Erklärung abgeben! Für Sprachen mit dem Do-While-Konstrukt ist es idomatischer:do { code that can conditionally break out } while (false);
Thomas Eding

10

Sie können die Funktionalität von goto mit Ausnahmen emulieren:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

Haftungsausschluss: Ich möchte Sie nur auf die Möglichkeit aufmerksam machen, Dinge auf diese Weise zu tun, während ich dies unter normalen Umständen in keiner Weise als angemessen befürworte. Wie ich in einem Kommentar zu dieser Frage erwähnt habe, ist es bei weitem vorzuziehen, Code so zu strukturieren, dass byzantinische Bedingungen überhaupt vermieden werden. :-)


Haha, ich mag diese kreative Lösung. Ich werde mich jedoch an Ihren Haftungsausschluss halten und keinen solchen funky Code verwenden.
Roman

@Roman: Gerne füge ich neben Shmoopty einen weiteren Trick hinzu - auch wenn ich mich im Vergleich ungezogen fühle. ;-)
Michał Marczyk

8

vielleicht das?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

1
Ja, das könnte funktionieren. Ich denke, meine Gedanken sind irgendwie ausgeblendet, elifals ich das geschrieben habe. Obwohl ich denke, dass dies in einer Situation nicht funktionieren würde, in der Code zwischen den verschachtelten if-Anweisungen ausgeführt werden soll.
Roman

Das ist eigentlich die richtige Antwort. Warum sehe ich keine Leute, die dies empfehlen? :)
kerbrose

6

Für das, was tatsächlich gefragt wurde, besteht mein Ansatz darin, diese ifs in eine Schleife mit einer Schleife zu setzen

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

Probier es aus:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

1
Um ehrlich zu sein, ist dies die sauberste Lösung. Es ist sehr klar, wann der Code beendet werden soll - Sie müssen sich keine Gedanken über den Funktionsumfang innerhalb von Funktionen machen, und es gibt keine Leistung oder logische Verschuldung.
Trent

2
Könnte in Betracht ziehen, for _ in range(1):anstelle von zu verwenden while True:. (1) Kommunizieren Sie besser Ihre Absicht einer einzelnen Iterationsschleife und (2) keine letzte Unterbrechungsanweisung zum Verlassen der Schleife (möglicherweise später versehentlich entfernt)
Bernhard Kausler

3

Im Allgemeinen nicht. Wenn Sie "Wenns" verschachteln und von ihnen abbrechen, machen Sie es falsch.

Wenn Sie jedoch müssen:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

Beachten Sie, dass die Funktionen nicht in der if-Anweisung deklariert werden MÜSSEN, sondern im Voraus deklariert werden können;) Dies wäre eine bessere Wahl, da es nicht erforderlich ist, ein hässliches if / dann später umzugestalten.


Danke für die Antwort. Ich bin mir nicht sicher, was Sie unter "Verschachtelungsschleifen" verstehen. Wenn Sie sich auf meine Erwähnung des Schlüsselworts 'break' beziehen, habe ich lediglich versucht, meine Suche nach einem If-Exit zu motivieren, indem ich es mit der Existenz eines Loop-Exits verglichen habe. Ich bin auch nicht sicher , wie Ihr Code das Problem löst, wie mein Beispiel hatte if condition_aund im if condition_bInnern einer verschachtelt if some_condition. Ich möchte aus dem ausbrechen können if some_condition.
Roman

Der Grund, warum Leute ifs verschachteln und brechen wollen, ist wahrscheinlich nicht, dass sie es falsch machen, sondern vielleicht, weil sie sauberen, einfachen und trockenen Code schreiben wollen. Ein einfacher Fall ist, wenn das Programm x () ausführen muss, wenn sowohl Bedingung_a als auch Bedingung_b erfüllt sind, und y () nur für Bedingung_a ausführen muss und z () nur für Bedingung_b ausführen muss. und der Codierer weigert sich, x ()
mehrmals

1

Tatsächlich beschreiben Sie goto-Anweisungen, die im Allgemeinen ziemlich stark verschoben werden. Ihr zweites Beispiel ist viel einfacher zu verstehen.

Sauberer wäre jedoch immer noch:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

1

Es gibt einen anderen Weg, der nicht auf der Definition von Funktionen beruht (da dies manchmal für kleine Codefragmente weniger lesbar ist), keine zusätzliche äußere while-Schleife verwendet (die möglicherweise eine besondere Berücksichtigung in den Kommentaren erfordert, um auf den ersten Blick verständlich zu sein). , verwendet kein goto (...) und vor allem können Sie Ihre Einrückungsstufe für das Äußere beibehalten, wenn Sie nicht mit dem Verschachteln beginnen müssen.

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

Ja, das erfordert auch einen zweiten Blick auf die Lesbarkeit. Wenn die Codeausschnitte jedoch klein sind, müssen keine while-Schleifen nachverfolgt werden, die sich nie wiederholen. Nachdem Sie verstanden haben, wofür die Zwischen-Ifs gedacht sind, ist sie leicht lesbar ein Ort und mit der gleichen Einkerbung.

Und es sollte ziemlich effizient sein.


0

Hier verstehe ich also, dass Sie versuchen, aus dem äußeren if-Codeblock auszubrechen

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

Ein Ausweg besteht darin, dass Sie im äußeren if-Block nach einer falschen Bedingung suchen können, die dann implizit aus dem Codeblock austritt. Anschließend verwenden Sie einen else-Block, um die anderen ifs zu verschachteln, um etwas zu tun

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

0

Das einzige, was dies ohne zusätzliche Methoden anwenden würde, ist elifdas folgende Beispiel

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

-1

Hier ist eine andere Möglichkeit, damit umzugehen. Es wird ein einzelnes Element für die Schleife verwendet, mit dem Sie einfach weiter verwenden können. Es verhindert, dass unnötige zusätzliche Funktionen ohne Grund erforderlich sind. Und eliminiert zusätzlich potenzielle unendliche while-Schleifen.

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

-2

Die Verwendung returnin der if-Bedingung gibt Sie aus der Funktion zurück, sodass Sie mit return die if-Bedingung aufheben können.


2
er will die Funktion brechen, wenn nicht
beenden
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.