Wie kann man aus mehreren Schleifen ausbrechen?

481

Angesichts des folgenden Codes (der nicht funktioniert):

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 #this doesn't work :(
        if ok.lower() == "n": break
    #do more processing with menus and stuff

Gibt es eine Möglichkeit, diese Arbeit zu machen? Oder muss ich eine Prüfung durchführen, um aus der Eingangsschleife auszubrechen, und eine andere, eingeschränktere Prüfung in der äußeren Schleife, um alle zusammen auszubrechen, wenn der Benutzer zufrieden ist?

Matthew Scharley
quelle
87
Warum hat Python nicht einfach 'break (n)', wobei n die Anzahl der Ebenen ist, aus denen Sie ausbrechen möchten.
Nathan
2
C ++ ist hier schön, gotowenn Sie tief in viele Schleifen eingebettet sind
Drake Johnson

Antworten:

512

Mein erster Instinkt wäre, die verschachtelte Schleife in eine Funktion umzuwandeln und returnzum Ausbrechen zu verwenden.

Robert Rossney
quelle
3
Dies ist ein weiterer Gedanke, den ich hatte, da eine get_input_yn () -Funktion auch anderswo nützlich wäre, da bin ich mir sicher.
Matthew Scharley
96
in diesem speziellen Fall vereinbart, aber im allgemeinen Fall von "Ich habe verschachtelte Schleifen, was mache ich" ist Refactoring möglicherweise nicht sinnvoll.
quick_dry
Die Verwendung einer Ausnahme ist möglicherweise einfacher, wenn Sie nachgeben müssen, anstatt return zu verwenden. In einem solchen Fall sollten Sie jedoch wahrscheinlich itertools.islice () verwenden.
Robert King
5
Es ist normalerweise möglich, die innere Schleife in eine eigene Methode umzuwandeln, die true zurückgibt, um fortzufahren, false, um die äußere Schleife zu unterbrechen. während Bedingung1: / wenn nicht MyLoop2 (Parameter): break. Eine Alternative besteht darin, ein boolesches Flag zu setzen, das auf beiden Ebenen getestet wird. more = True / while Bedingung1 und mehr: / while Bedingung2 und mehr: / if stopCondition: more = False / break / ...
ToolmakerSteve
7
Ich stimme zu, dass das Streben nach Verwendung returnder richtige Ansatz ist. Und die Argumentation ist, dass nach dem Zen von Python "flach besser ist als verschachtelt". Wir haben hier drei Verschachtelungsebenen, und wenn dies in die Quere kommt, ist es an der Zeit, die Verschachtelung zu reduzieren oder zumindest die gesamte Verschachtelung in eine eigene Funktion zu extrahieren.
Lutz Prechelt
240

Hier ist ein weiterer Ansatz, der kurz ist. Der Nachteil ist, dass Sie nur die äußere Schleife brechen können, aber manchmal ist es genau das, was Sie wollen.

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

Dies verwendet das for / else-Konstrukt, das unter erklärt wird: Warum verwendet Python 'else' nach for- und while-Schleifen?

Schlüsselerkenntnis: Es scheint nur so, als ob die äußere Schleife immer bricht. Aber wenn die innere Schleife nicht bricht, wird auch die äußere Schleife nicht brechen.

Die continueAussage ist die Magie hier. Es steht in der For-else-Klausel. Per Definition passiert das, wenn es keine innere Unterbrechung gibt. In dieser Situation wird continueder äußere Bruch sauber umgangen.

Yak
quelle
6
@ Eugeney Warum nicht? Die erste Pause wird aus der inneren Schleife herauskommen.
Navin
5
@ Eugeney Ich habe das Gefühl, dass mir hier etwas fehlt. Können Sie ein Beispiel posten?
Navin
4
@Mingliang das kann vor dem weitergehen gehen.
Baldrickk
1
Erhalten Sie dies aus einem Raymond Hettinger-Video, youtu.be/OSGv2VnC0go?t=971 , lesen Sie "else" -Anweisungen , die für for-Schleifen als "no_break" angehängt sind, dann wird es einfacher zu verstehen.
Ambareesh
2
Das ist klug. :-) Allerdings nicht einfach. Ehrlich gesagt bin ich nicht von Argumenten überzeugt, beschriftet break oder break (n) aus Python herauszuhalten. Die Problemumgehungen erhöhen die Komplexität.
rfportilla
148

PEP 3136 schlägt die Bezeichnung break / continue vor. Guido lehnte es ab, weil "Code, der so kompliziert ist, dass er diese Funktion benötigt, sehr selten ist". Das PEP erwähnt jedoch einige Problemumgehungen (wie die Ausnahmetechnik), während Guido der Ansicht ist, dass die Umgestaltung zur Verwendung der Rückgabe in den meisten Fällen einfacher sein wird.

John Fouhy
quelle
73
Obwohl Refactor / returnnormalerweise der richtige Weg ist, habe ich einige Fälle gesehen, in denen eine einfache, prägnante break 2Aussage einfach so viel Sinn machen würde. Auch Refactor / returnfunktioniert nicht gleich für continue. In diesen Fällen ist das numerische Unterbrechen und Fortfahren einfacher zu verfolgen und weniger überladen als das Umgestalten einer winzigen Funktion, das Auslösen von Ausnahmen oder die verschlungene Logik, bei der ein Flag gesetzt wird, um auf jeder Verschachtelebene zu unterbrechen. Es ist eine Schande, dass Guido es abgelehnt hat.
James Haigh
10
break; breakwäre nett.
PyRulez
5
@Jeyekomon Das Problem ist, dass Sie nicht 3 oder mehr verschachtelte Schleifen benötigen, damit dies ein Problem darstellt. 2 verschachtelte Schleifen sind ziemlich häufig
Jon
6
"Code, der so kompliziert ist, dass er diese Funktion benötigt, ist sehr selten". Wenn Sie jedoch jemals so komplizierten Code verwenden, wird das Fehlen beschrifteter Schleifen das Ganze noch komplizierter, da Sie breakdie Schleifen manuell durch alle Schleifen weiterleiten müssen . Blöd.
BallpointBen
3
Anscheinend kann ich einen Beitrag nur 5 Minuten lang bearbeiten (es war 6). Also, hier ist mein bearbeiteter Beitrag: Meine 2 Cent: Perl hat break (aber nennt es "last") und "next" markiert, um direkt mit der nächsten Iteration fortzufahren. Es ist überhaupt nicht selten - ich benutze es die ganze Zeit. Ich bin brandneu in Python und brauche es bereits. Außerdem wären nummerierte Unterbrechungen für das Refactoring schrecklich. Beschriften Sie besser die Schleife, aus der Sie ausbrechen möchten, und verwenden Sie dann break <label>, um explizit anzugeben, aus welcher Schleife Sie ausbrechen möchten.
John Deighan
119

Erstens ist gewöhnliche Logik hilfreich.

Wenn die Kündigungsbedingungen aus irgendeinem Grund nicht geklärt werden können, handelt es sich bei Ausnahmen um einen Fallback-Plan.

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

Für dieses spezielle Beispiel ist möglicherweise keine Ausnahme erforderlich.

Andererseits haben wir in Zeichenmodusanwendungen häufig die Optionen "Y", "N" und "Q". Für die Option "Q" möchten wir einen sofortigen Ausstieg. Das ist außergewöhnlicher.

S.Lott
quelle
4
Im Ernst, Ausnahmen sind extrem billig und idiomatische Python verwendet viele, viele von ihnen. Es ist auch sehr einfach, benutzerdefinierte zu definieren und zu werfen.
Gregg Lind
13
Interessante Idee. Ich bin hin und her gerissen, ob ich es lieben oder hassen soll.
Craig McQueen
8
Diese Lösung wäre hilfreicher, wenn die beiden Varianten getrennt dargestellt würden. (1) Verwenden eines Flags ( done). (2) Auslösen einer Ausnahme. Durch das Zusammenführen zu einer einzigen Lösung sieht es nur kompliziert aus. Für zukünftige Leser: Verwenden Sie entweder alle Zeilen, die betreffen done, ODER definieren GetOutOfLoop(Exception)und erhöhen / außer dem.
ToolmakerSteve
4
Im Allgemeinen ist die Verwendung von Try-Blöcken für andere als Ausnahmen sehr verpönt. Try-Blöcke wurden speziell für die Fehlerbehandlung entwickelt, und ihre Verwendung für einen seltsamen Kontrollfluss ist stilistisch nicht sehr gut.
Nobillygreen
3
@ tommy.carstensen Das ist Unsinn; Sowohl das Definieren einer neuen Ausnahmeunterklasse als auch das Auslösen (wie in der Antwort gezeigt) und das Übergeben einer benutzerdefinierten Nachricht an den ExceptionKonstruktor (z. B. raise Exception('bla bla bla')) sind sowohl in Python 2 als auch in Python 3 gültig. Ersteres ist in diesem Fall vorzuziehen, da wir dies nicht möchten Unser exceptBlock zum Abfangen aller Ausnahmen, aber nur der speziellen Ausnahme, mit der wir die Schleife verlassen. Wenn wir die Dinge so tun, wie Sie es vorschlagen, und dann ein Fehler in unserem Code dazu führt, dass eine unerwartete Ausnahme ausgelöst wird, wird dies fälschlicherweise genauso behandelt wie das absichtliche Verlassen der Schleife.
Mark Amery
54

Ich stimme eher zu, dass das Refactoring in eine Funktion normalerweise der beste Ansatz für diese Art von Situation ist. Wenn Sie jedoch wirklich aus verschachtelten Schleifen ausbrechen müssen, finden Sie hier eine interessante Variante des von @ S.Lott beschriebenen Ansatzes zum Auslösen von Ausnahmen. Es verwendet Pythons withAnweisung, um das Auslösen von Ausnahmen ein bisschen schöner zu machen. Definieren Sie einen neuen Kontextmanager (Sie müssen dies nur einmal tun) mit:

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

Jetzt können Sie diesen Kontextmanager wie folgt verwenden:

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

Vorteile: (1) Es ist etwas sauberer (kein expliziter Try-außer-Block) und (2) Sie erhalten eine benutzerdefinierte ExceptionUnterklasse für jede Verwendung von nested_break; Sie müssen nicht Exceptionjedes Mal Ihre eigene Unterklasse deklarieren .

Mark Dickinson
quelle
40

Zunächst können Sie auch in Betracht ziehen, den Prozess zum Abrufen und Validieren der Eingabe zu einer Funktion zu machen. Innerhalb dieser Funktion können Sie den Wert einfach zurückgeben, wenn er korrekt ist, und wenn nicht , in der while- Schleife weiterdrehen. Dies vermeidet im Wesentlichen das von Ihnen gelöste Problem und kann normalerweise im allgemeineren Fall angewendet werden (Ausbrechen mehrerer Schleifen). Wenn Sie diese Struktur unbedingt in Ihrem Code behalten müssen und sich wirklich nicht mit Buchhaltungs-Booleschen Werten befassen möchten ...

Sie können goto auch folgendermaßen verwenden (mit einem April Fools-Modul von hier ):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

Ich weiß, ich weiß, "du sollst nicht goto verwenden" und all das, aber es funktioniert gut in seltsamen Fällen wie diesen.

Matt J.
quelle
1
Wenn es etwas wie der Befehl COME FROM in INTERCAL ist, dann nichts
1800 INFORMATION
3
Ich mag den Witz, aber der Punkt des Stapelüberlaufs ist, guten Code zu fördern, also muss ich Sie abstimmen :(
Christian Oudard
13
Ich denke, es ist eine saubere und lesbare Lösung, um als guter Code zu gelten, also stimme ich ab. :)
JT Hurley
1
@JTHurley nein das ist nicht sauber und lesbar. Ich meine, es mag in diesem Beispiel so aussehen, als wäre es sauber und lesbar, aber in jedem realen Szenario schafft goto ein heiliges Durcheinander . (Auch das ist sooo anti-pythonisch ...)
Alois Mahdal
2
goto bekommt einen schlechten Ruf, jeder professionelle Programmierer sollte meiner Meinung nach in der Lage sein, richtig damit umzugehen.
Albert Renshaw
33

Führen Sie eine neue Variable ein, die Sie als "Loop Breaker" verwenden. Weisen Sie ihm zuerst etwas zu (False, 0 usw.) und ändern Sie dann innerhalb der äußeren Schleife, bevor Sie davon abbrechen, den Wert in etwas anderes (True, 1, ...). Sobald die Schleife beendet ist, überprüfen Sie die 'übergeordnete' Schleife auf diesen Wert. Lassen Sie mich demonstrieren:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

Wenn Sie eine Endlosschleife haben, ist dies der einzige Ausweg. Bei anderen Schleifen ist die Ausführung sehr viel schneller. Dies funktioniert auch, wenn Sie viele verschachtelte Schleifen haben. Sie können alle oder nur einige beenden. Endlose Möglichkeiten! Hoffe das hat geholfen!

krvolok
quelle
22

Verwenden Sie eine "simulierte goto-Anweisung" mit der integrierten StopIteration-Ausnahme , um aus mehreren verschachtelten Schleifen auszubrechen, ohne sie in eine Funktion umzuwandeln :

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

In dieser Diskussion wird die Verwendung von goto-Anweisungen zum Aufbrechen verschachtelter Schleifen beschrieben.

Genauso wie
quelle
1
Dies sieht viel besser aus als das Erstellen einer eigenen Klasse, um die Ausnahme zu behandeln, und sieht sehr sauber aus. Gibt es einen Grund, warum ich das nicht tun sollte?
mgjk
Tatsächlich wird StopIteration für Generatoren verwendet, aber ich denke, normalerweise gibt es keine nicht abgefangene StopIteration-Ausnahme. Es scheint also eine gute Lösung zu sein, aber es ist trotzdem kein Fehler, eine neue Ausnahme zu erstellen.
Kowalski
1
Beste und einfachste Lösung für mich
Alexandre Huat
16

keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

oder etwas ähnliches. Sie können eine Variable in der inneren Schleife festlegen und sie unmittelbar nach dem Beenden der inneren Schleife in der äußeren Schleife überprüfen und gegebenenfalls unterbrechen. Ich mag die GOTO-Methode, vorausgesetzt, es macht Ihnen nichts aus, ein Aprilscherz-Modul zu verwenden - es ist nicht pythonisch, aber es macht Sinn.

schnelltrocknend
quelle
Das ist eine Art Flaggeneinstellung!
Islam
Ich denke, es ist eine sehr gute Lösung.
Kowalski
13

Dies ist nicht der schönste Weg, aber meiner Meinung nach ist es der beste Weg.

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

Ich bin mir ziemlich sicher, dass Sie auch hier etwas mit Rekursion herausfinden können, aber ich weiß nicht, ob das eine gute Option für Sie ist.

Jason Baker
quelle
Das war die richtige Lösung für mich. Mein Anwendungsfall war ganz anders als der der OPs. Ich habe im Wesentlichen dieselben Daten zweimal durchlaufen, um Permutationen zu finden, daher wollte ich die beiden while-Schleifen nicht trennen.
Brian Peterson
9

Und warum nicht weiter schleifen, wenn zwei Bedingungen erfüllt sind? Ich denke, das ist ein pythonischerer Weg:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

Ist es nicht?

Alles Gute.

Mauro Aspé
quelle
warum nicht einfach while dejaVu:? Sie setzen es trotzdem auf true.
Matthew Scharley
Hey das funktioniert! Ich habe unter zwei TrueBedingungen darüber nachgedacht , zwei Schleifen zu überspringen, aber nur eine ist genug.
Mauro Aspé
2
@MatthewScharley Ich denke, dies soll zeigen, dass dies in verschachtelten Schleifen funktioniert.
behandeln
@ MauroAspé dies wird nicht genau das tun, was das OP verlangt. Es wird immer noch die gesamte äußere Schleife ausgeführt, aber das Ziel ist, dass der Rest des Codes nicht ausgeführt wird, wenn Sie den Rest brechen
yamm
@yamm Könnte das nicht mit einem if not dejaVu: breakunten gelöst werden und damit die Hauptschleife verlassen? Ich denke, die Lösung kommt der Frage am nächsten. +1
Milcak
8

Berücksichtigen Sie Ihre Schleifenlogik in einem Iterator, der die Schleifenvariablen liefert und nach Abschluss zurückgibt. Hier ist eine einfache Methode, die Bilder in Zeilen / Spalten anordnet, bis keine Bilder mehr vorhanden sind oder keine Stellen mehr vorhanden sind, an denen sie abgelegt werden können:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

Dies hat den Vorteil, dass die komplizierte Schleifenlogik und die Verarbeitung ...

Matt Billenstein
quelle
3

In diesem Fall ist, wie auch von anderen betont, die funktionale Zerlegung der richtige Weg. Code in Python 3:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break
Scherz
quelle
3

In der Python- while ... elseStruktur gibt es einen versteckten Trick, mit dem die doppelte Unterbrechung ohne große Codeänderungen / -ergänzungen simuliert werden kann. Wenn die whileBedingung falsch ist, wird der elseBlock im Wesentlichen ausgelöst. Weder Ausnahmen continuenoch breakden elseBlock auslösen . Weitere Informationen finden Sie unter Antworten auf " Else-Klausel in Python while-Anweisung " oder in Python doc on while (v2.7) .

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

Der einzige Nachteil ist, dass Sie die Doppelbruchbedingung in die whileBedingung verschieben müssen (oder eine Flagvariable hinzufügen müssen). Variationen davon gibt es auch für die forSchleife, bei der der elseBlock nach Abschluss der Schleife ausgelöst wird.

holroy
quelle
Dies scheint die Anforderung von Doppelpausen nicht zu erfüllen. Funktioniert für das genau gegebene Problem, aber nicht für die eigentliche Frage.
Dakkaron
@ Dakkaron Bist du sicher, dass du den Code richtig verstanden hast? Der Code löst tatsächlich die OP-Frage und bricht ähnlich wie bei der Anfrage ab. Es bricht jedoch nicht aus mehreren Schleifen aus, sondern verwendet die else-Klausel, um die Notwendigkeit einer Verdoppelung der Unterbrechung zu ersetzen.
Holroy
How to break out of multiple loops in Python?Nach meinem Verständnis war die Frage und die Antwort hätte lauten sollen: "Es funktioniert nicht, probieren Sie etwas anderes aus." Ich weiß, dass es das genau gegebene Beispiel des OP behebt, aber ihre Frage nicht beantwortet.
Dakkaron
@ Dakkaron, siehe die Problemstellung unter dem Code, und meiner Meinung nach beantwortet sie tatsächlich die Frage des OP.
Holroy
2

Eine andere Möglichkeit, Ihre Iteration auf eine einstufige Schleife zu reduzieren, besteht in der Verwendung von Generatoren, wie auch in der Python-Referenz angegeben

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

Sie können es für die Schleife auf eine beliebige Anzahl von Ebenen skalieren

Der Nachteil ist, dass Sie nicht mehr nur ein einziges Level durchbrechen können. Alles oder Nichts.

Ein weiterer Nachteil ist, dass es mit einer while-Schleife nicht funktioniert. Ich wollte diese Antwort ursprünglich auf Python posten - `break` aus allen Schleifen, aber leider ist das als Duplikat dieser geschlossen

Peeyush Kushwaha
quelle
1
Es funktioniert auch für while-Schleifen. Sie müssen Ihren Generator nur als Def (mit Ertrag) schreiben, nicht als Verständnis.
Veky
Ja, ein Sprecher einer PyCon behauptet hier, dass selbst die von @ RobertRossney akzeptierte Antwort nicht wirklich pythonisch ist, aber ein Generator der richtige Weg ist, um mehrere Schleifen zu durchbrechen. (Ich würde empfehlen, das ganze Video
anzuschauen
2

Mein Grund, hierher zu kommen, ist, dass ich eine äußere und eine innere Schleife hatte:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

Wie Sie sehen können, geht es nicht zum nächsten x, sondern zum nächsten y.

Um dies zu lösen, musste ich das Array stattdessen zweimal durchlaufen:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

Ich weiß, dass dies ein spezieller Fall von OPs Frage war, aber ich poste ihn in der Hoffnung, dass er jemandem hilft, über sein Problem anders nachzudenken und die Dinge einfach zu halten.

Nathan Garabedian
quelle
Dies ist wahrscheinlich nicht Python. Was ist die Art des Arrays? Wahrscheinlich Liste, aber was enthält es? Selbst wenn es Ints enthält, wird array.pop (x) wahrscheinlich nicht das tun, was Sie wollen.
Veky
Das ist ein guter Punkt. Ich kann den Code, auf den ich verwiesen habe, nicht finden. Für alle, die dies lesen, array.pop (i) "Entfernt das Element mit dem Index i aus dem Array und gibt es zurück." gemäß Python-Dokumentation. Man müsste also den Index von Element x im Array abrufen, damit dieser Code wie erwartet funktioniert. Es gibt auch die Funktion array.remove (x), die das tun würde, was erwartet wird. Ich werde meine Antwort oben ändern, um diesen Fehler zu beheben. Dies setzt voraus, dass das zweite Array keine Duplikate enthält, da array.remove (x) nur die erste gefundene x-Instanz entfernt.
Nathan Garabedian
Ok, dann verstehe ich es. In diesem Fall würde eine einfache Verwendung breakanstelle von continuedas tun, was Sie wollen, nicht wahr? :-)
Veky
Ja, aus Gründen der Effizienz und Klarheit möchten Sie wahrscheinlich break verwenden, anstatt in diesen Beispielen fortzufahren. :)
Nathan Garabedian
2

Versuchen Sie es mit einem unendlichen Generator.

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff
Robert King
quelle
2

Mit einer Funktion:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

Versuchen Sie, die obigen Codes auszuführen, indem Sie auch die auskommentieren return.

Ohne Verwendung einer Funktion:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

Führen Sie nun die obigen Codes wie bisher aus und versuchen Sie dann, jede Zeile, die jeweils eine Zeile enthält, breakvon unten auskommentieren.

Rafiq
quelle
2

Eine einfache Möglichkeit, mehrere Schleifen in eine einzige, zerbrechliche Schleife umzuwandeln, ist die Verwendung numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

Sie müssen in Ihre Objekte indizieren, anstatt die Werte explizit durchlaufen zu können, aber zumindest in einfachen Fällen scheint es ungefähr 2-20 Mal einfacher zu sein als die meisten der vorgeschlagenen Antworten.

one_observation
quelle
2
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on
RufusVS
quelle
1

Wahrscheinlich reicht ein kleiner Trick wie unten, wenn Sie es nicht vorziehen, in die Funktion umzugestalten

1 break_level-Variable hinzugefügt, um die while-Schleifenbedingung zu steuern

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level
Skycc
quelle
1

Sie können eine Variable definieren (z. B. break_statement ), sie dann in einen anderen Wert ändern, wenn eine Zwei-Unterbrechungsbedingung auftritt, und sie in der if-Anweisung verwenden, um auch von der zweiten Schleife abzubrechen.

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break
Helms Klamm
quelle
Guter Punkt, aber in jeder Ebene über unserer inneren Ebene von Interesse müssten wir diese Variable scannen. Fühlt sich wirklich schlecht an, dass die Sprache keine GoTo-Anweisung hat, was die Leistung betrifft.
Anatoly Alekseev
1

Ich möchte Sie daran erinnern, dass Funktionen in Python direkt in der Mitte des Codes erstellt werden können und transparent auf die umgebenden Variablen zum Lesen und mit nonlocaloder globalDeklaration zum Schreiben zugreifen können .

Sie können also eine Funktion als "zerbrechliche Kontrollstruktur" verwenden und einen Ort definieren, an den Sie zurückkehren möchten:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4
Benutzer
quelle
1

Lösungen auf 2 Arten

Mit einem Beispiel: Sind diese beiden Matrizen gleich / gleich?
Matrix1 und Matrix2 haben die gleiche Größe, n, 2 dimensionale Matrizen.

Erste Lösung , ohne Funktion

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

Zweite Lösung , mit einer Funktion
Dies ist die letzte Lösung für meinen Fall

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

Einen schönen Tag noch!

Harun Altay
quelle
1
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff
RufusVS
quelle
0

Hoffentlich hilft das:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one
Daniel L.
quelle
0

Hier ist eine Implementierung, die zu funktionieren scheint:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

Der einzige Nachteil ist, dass Sie break_vor den Schleifen definieren müssen .

Fateh
quelle
0

Es gibt keine Möglichkeit, dies auf Sprachniveau zu tun. Einige Sprachen haben ein Problem, andere haben eine Pause, die ein Argument erfordert, Python nicht.

Die besten Optionen sind:

  1. Setzen Sie ein Flag, das von der äußeren Schleife überprüft wird, oder setzen Sie die Bedingung für die äußeren Schleifen.

  2. Fügen Sie die Schleife in eine Funktion ein und brechen Sie mit return alle Schleifen gleichzeitig aus.

  3. Formulieren Sie Ihre Logik neu.

Der Kredit geht an Vivek Nagarajan, Programmierer seit 1987


Funktion verwenden

def doMywork(data):
    for i in data:
       for e in i:
         return 

Flag verwenden

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break
Muhammad Faizan Fareed
quelle
-3

Ähnlich wie zuvor, aber kompakter. (Boolesche Werte sind nur Zahlen)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !
alu5
quelle
2
Dies sieht ziemlich hässlich aus und macht den Code im Vergleich zum vorherigen schwieriger zu verstehen. Es ist auch falsch. Es wird nicht überprüft, ob die Eingabe akzeptabel ist, und es wird nach 1 Schleife unterbrochen.
Eric
-3

Da diese Frage zu einer Standardfrage für das Einbrechen in eine bestimmte Schleife geworden ist, möchte ich meine Antwort anhand eines Beispiels geben Exception .

Obwohl es in Konstrukten mit mehreren Schleifen keine Bezeichnung mit dem Namen "Breaking of Loop" gibt, können wir benutzerdefinierte Ausnahmen verwenden , um in eine bestimmte Schleife unserer Wahl einzubrechen . Betrachten Sie das folgende Beispiel, in dem wir alle Zahlen mit bis zu 4 Ziffern im Basis-6-Nummerierungssystem drucken:

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

Wenn wir die Ausgabe drucken, erhalten wir niemals einen Wert, dessen Einheitsplatz bei 4 liegt. In diesem Fall brechen wir keine Schleife ab, BreakLoop(4)die ausgelöst und in derselben Schleife abgefangen wird. In ähnlicher Weise brechen wir immer dann, wenn zehn Plätze 3 haben, mit in die dritte Schleife einBreakLoop(3) . Immer wenn hundert BreakLoop(2)Stellen 5 haben, brechen wir mit in die zweite Schleife ein, und wenn die tausend Stellen 2 haben, brechen wir mit in die erste Schleife einBreakLoop(1) .

Kurz gesagt, erhöhen Sie Ihre Ausnahme (eingebaut oder benutzerdefiniert) in den inneren Schleifen und fangen Sie sie in der Schleife ab, von der aus Sie Ihre Kontrolle wieder aufnehmen möchten. Wenn Sie alle Schleifen unterbrechen möchten, fangen Sie die Ausnahme außerhalb aller Schleifen ab. (Ich habe diesen Fall im Beispiel nicht gezeigt).

Prasad
quelle