Gegeben der folgende Code (der nicht funktioniert):
while True:
#snip: print out current state
while True:
ok = get_input("Is this ok? (y/n)")
if ok == "y" or ok == "Y": break 2 #this doesn't work :(
if ok == "n" or ok == "N": break
#do more processing with menus and stuff
Gibt es eine Möglichkeit, dies zu erreichen? Oder muss ich eine Überprüfung durchführen, um die Eingabeschleife zu durchbrechen, dann eine andere, begrenztere, die äußere Schleife, um alle zu durchbrechen, wenn der Benutzer zufrieden ist?
Edit-FYI: get_input ist eine kurze Funktion, die ich geschrieben habe und die Anzeige von Eingabeaufforderungen und Standardwerten sowie alle diese Phantasie und Rückgabewerte unterstützt. stdin.readline().strip()
Mein erster Instinkt wäre, die verschachtelte Schleife in eine Funktion umzuwandeln und return
zu verwenden.
Hier ist ein weiterer Ansatz, der kurz ist. Der Nachteil ist, dass Sie nur die äußere Schleife durchbrechen 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
Hierfür wird das Konstrukt for/else verwendet, das unter folgender Adresse erläutert wird: Warum verwendet python 'else' nach for- und while-Schleifen?
Key Insight: Es scheint nur , als ob die äußere Schleife immer bricht. Aber wenn die innere Schleife nicht reißt, reißt auch die äußere Schleife nicht.
Die continue
-Anweisung ist hier die Magie. Es ist in der For-else-Klausel. Per Definition das passiert, wenn es keinen inneren Bruch gibt. In dieser Situation umgeht continue
den äußeren Bruch sauber.
PEP 3136 schlägt die Bezeichnung break/continue vor. Guido lehnte es ab weil "Code, der für diese Funktion so kompliziert ist, sehr selten ist". Das PEP erwähnt jedoch einige Problemumgehungen (z. B. die Ausnahmetechnik), während Guido der Meinung ist, dass das Refactoring für die Verwendung von return in den meisten Fällen einfacher ist.
Erstens ist gewöhnliche Logik hilfreich.
Wenn aus irgendeinem Grund die Beendigungsbedingungen nicht herausgearbeitet werden können, handelt es sich bei den Ausnahmen um einen Rückfallplan.
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 den Zeichenmodusanwendungen oft die Optionen "Y", "N" und "Q". Für die Option "Q" möchten wir sofort beenden. Das ist außergewöhnlicher.
Ich stimme eher zu, dass Refactoring in einer Funktion normalerweise der beste Ansatz für diese Art von Situation ist, aber für den Fall, dass Sie wirklich aus verschachtelten Schleifen ausbrechen müssen, ist hier eine interessante Variante des Ansatzes zum Auslösen von Ausnahmen das hat @ s.lott beschrieben. Es verwendet die with
-Anweisung von Python, um die Ausnahmebedingung ein bisschen besser aussehen zu lassen. 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-except-Block), und (2) Sie erhalten eine benutzerdefinierte Exception
-Unterklasse für jede Verwendung von nested_break
; Sie müssen nicht jedes Mal Ihre eigene Exception
-Unterklasse deklarieren.
Erstens können Sie auch erwägen, den Vorgang des Abrufs und der Überprüfung der Eingabe als Funktion zu definieren. Innerhalb dieser Funktion können Sie den Wert einfach zurückgeben, wenn er korrekt ist, und sich in der while -Schleife drehen, wenn dies nicht der Fall ist. Dies beseitigt im Wesentlichen das Problem, das Sie gelöst haben, und kann normalerweise im allgemeineren Fall angewendet werden (Ausbruch mehrerer Schleifen). Wenn Sie diese Struktur unbedingt in Ihrem Code beibehalten müssen und sich wirklich nicht mit buchhalterischen Booleschen befassen wollen ...
Sie können goto auch folgendermaßen verwenden (mit einem Aprilscherz-Modul aus 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 goto nicht verwenden" und all das, aber es funktioniert gut in so seltsamen Fällen.
Führen Sie eine neue Variable ein, die Sie als "Schleifenbrecher" verwenden. Weisen Sie ihm zuerst etwas zu (False, 0 usw.), und ändern Sie dann innerhalb der äußeren Schleife den Wert in etwas anderes (True, 1, ...). Sobald die Schleife beendet ist, prüfen Sie die 'Eltern'-Schleife auf diesen Wert. Lass 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. Für andere Loops ist die Ausführung wirklich viel schneller. Dies funktioniert auch, wenn Sie viele verschachtelte Schleifen haben. Sie können alle oder nur wenige beenden. Endlose Möglichkeiten! Hoffe das hat geholfen!
keeplooping=True
while keeplooping:
#Do Stuff
while keeplooping:
#do some other stuff
if finisheddoingstuff(): keeplooping=False
oder sowas ähnliches. Sie können eine Variable in der inneren Schleife festlegen und diese unmittelbar nach dem Verlassen der inneren Schleife in der äußeren Schleife überprüfen. Ich mag die GOTO-Methode, vorausgesetzt, es macht Ihnen nichts aus, ein Witzmodul von April Fool zu verwenden - es ist nicht Pythonic, aber es macht Sinn.
Das ist nicht der schönste Weg, aber meiner Meinung nach 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 ausarbeiten könnten, aber ich weiß nicht, ob das eine gute Option für Sie ist.
Um aus mehreren verschachtelten Schleifen auszubrechen, ohne in eine Funktion umgewandelt zu werden, verwenden Sie eine "simulierte goto-Anweisung" mit der integrierten StopIteration-Ausnahme :
try:
for outer in range(100):
for inner in range(100):
if break_early():
raise StopIteration
except StopIteration: pass
Siehe diese Diskussion über die Verwendung von goto-Anweisungen zum Ausbrechen von verschachtelten Schleifen.
Berechnen Sie Ihre Schleifenlogik in einen Iterator, der die Schleifenvariablen liefert und zurückgibt, wenn Sie fertig sind. Hier ist eine einfache, die Bilder in Zeilen/Spalten anordnet, bis wir keine Bilder mehr haben oder außerhalb von Orten, um sie zu platzieren:
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 ...
Und warum sollte man nicht weiterlaufen, wenn zwei Bedingungen zutreffen?
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.
In diesem Fall, wie auch von anderen aufgezeigt, ist funktionelle Zerlegung der 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
In der Python while ... else
-Struktur gibt es einen versteckten Trick, mit dem der doppelte Umbruch ohne viel Codeänderungen ergänzungen simuliert werden kann. Wenn im Wesentlichen die while
-Bedingung falsch ist, wird der else
-Block ausgelöst. Keine der Ausnahmen, continue
oder break
, löst den else
-Block aus. Weitere Informationen finden Sie in den Antworten auf "/ - Else-Klausel auf Python while-Anweisung " oder auf 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 doppelte Unterbrechungsbedingung in die while
-Bedingung verschieben müssen (oder eine Flag-Variable hinzufügen). Variationen davon gibt es auch für die for
-Schleife, bei der der else
-Block nach Abschluss der Schleife ausgelöst wird.
Eine andere Möglichkeit, die Iteration auf eine einstufige Schleife zu reduzieren, besteht in der Verwendung von Generatoren, die ebenfalls in der Referenz python angegeben sind.
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 Stufen skalieren
Der Nachteil ist, dass Sie nicht mehr nur eine Ebene brechen können. Alles oder Nichts.
Ein weiterer Nachteil ist, dass es nicht mit einer while-Schleife funktioniert. Ich wollte diese Antwort ursprünglich auf Python - "break" aus allen Schleifen posten, aber leider ist dies als Duplikat dieser hier geschlossen
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, geht es nicht wirklich zum nächsten x, sondern zum nächsten y.
um dies zu lösen, musste ich einfach zweimal durch das Array laufen:
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 es in der Hoffnung, dass es jemandem helfen wird, sein Problem anders zu denken und dabei die Dinge einfach zu halten.
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()
Führen Sie die obigen Codes aus, indem Sie auch die Variable return
auskommentieren.
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 aus, und starten Sie dann die Ausführung, indem Sie jede Zeile, die break
enthält, einzeln von unten auskommentieren.
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
wahrscheinlich wird ein kleiner Trick wie unten, wenn nicht lieber in die Funktion umgestaltet
1 Variable break_level 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
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
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
Sie können eine Variable definieren (z. B. break_statement ) und sie dann in einen anderen Wert ändern, wenn eine Zwei-Break-Bedingung auftritt, und sie in der if-Anweisung verwenden, um auch die zweite Schleife zu unterbrechen.
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
Eine einfache Möglichkeit, mehrere Schleifen in eine einzelne, zerbrechliche Schleife zu verwandeln, ist 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 in einfachen Fällen scheint es ungefähr 2-20-mal einfacher als die meisten vorgeschlagenen Antworten zu sein.
Ich möchte Sie daran erinnern, dass Funktionen in Python direkt in der Mitte des Codes erstellt werden können und auf die Umgebungsvariablen transparent zum Lesen und mit der Erklärung nonlocal
oder global
zum Schreiben zugreifen können.
Sie können also eine Funktion als "zerbrechliche Kontrollstruktur" verwenden, die einen Ort definiert, zu dem 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
Mit einem Beispiel: Sind diese beiden Matrizen gleich?
Matrix1 und Matrix2 haben dieselbe 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 endgültige 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!
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