¿Cómo salir de múltiples bucles?


482

Dado el siguiente código (que no funciona):

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

¿Hay alguna manera de hacer que esto funcione? ¿O tengo que hacer una verificación para salir del bucle de entrada, luego otra, más limitada, verificar en el bucle exterior para salir todos juntos si el usuario está satisfecho?


87
¿Por qué Python no solo tiene 'break (n)' donde n es la cantidad de niveles de los que quieres salir?
Nathan

2
C ++ es bueno aquí gotosi estás enclavado en muchos bucles
Drake Johnson

Respuestas:


512

Mi primer instinto sería refactorizar el bucle anidado en una función y usar returnpara romper.


3
Este es otro pensamiento que tuve, ya que una función get_input_yn () también sería útil en otro lugar, estoy seguro.
Matthew Scharley

96
acordado en este caso específico, pero en el caso general de la refactorización "He anidado bucles, qué hago" puede no tener sentido.
quick_dry

usar una excepción puede ser más fácil cuando debe ceder en lugar de usar return, sin embargo, probablemente debería usar itertools.islice () en tal caso.
Robert King

55
Por lo general, es posible refactorizar el bucle interno en su propio método, que devuelve verdadero para continuar, falso para romper el bucle externo. while condition1: / if not MyLoop2 (params): break. Una alternativa es establecer una bandera booleana, que se prueba en ambos niveles. more = True / while condition1 y más: / while condition2 y más: / if stopCondition: more = False / break / ...
ToolmakerSteve

77
Estoy de acuerdo en que esforzarse por usar returnes el enfoque correcto. Y el razonamiento es que, según el Zen de Python , "plano es mejor que anidado". Tenemos tres niveles de anidamiento aquí y si eso comienza a interferir, es hora de reducir el anidamiento o al menos extraer todo el anidamiento en una función propia.
Lutz Prechelt

240

Aquí hay otro enfoque que es corto. La desventaja es que solo puedes romper el bucle externo, pero a veces es exactamente lo que quieres.

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

Esto usa la construcción for / else explicada en: ¿Por qué Python usa 'else' después de los bucles for y while?

Visión clave: solo parece que el bucle externo siempre se rompe. Pero si el bucle interno no se rompe, el bucle externo tampoco lo hará.

La continuedeclaración es la magia aquí. Está en la cláusula for-else. Por definición, eso sucede si no hay una ruptura interna. En esa situación, continueelude cuidadosamente la ruptura exterior.


66
@eugeney ¿Por qué no? El primer descanso saldrá del circuito interno.
Navin

55
@eugeney Siento que me falta algo aquí. Puede publicar un ejemplo?
Navin

44
@Mingliang que puede ir antes de continuar.
Baldrickk

1
Obtuve esto de un video de Raymond Hettinger, youtu.be/OSGv2VnC0go?t=971 , lee las declaraciones "else" adjuntas para bucles como "no_break", luego se vuelve más fácil de entender.
Ambareesh

2
Esto es inteligente :-) Sin embargo, no es sencillo. Francamente, no estoy convencido por los argumentos para mantener etiquetado break o break (n) fuera de Python. Las soluciones agregan más complejidad.
rfportilla 01 de

148

PEP 3136 propone rotura de descanso / continuar. Guido lo rechazó porque "el código tan complicado que requiere esta función es muy raro". Sin embargo, el PEP menciona algunas soluciones alternativas (como la técnica de excepción), mientras que Guido considera que la refactorización para usar el retorno será más simple en la mayoría de los casos.


73
Aunque, refactorizar / returnes generalmente el camino a seguir, he visto bastantes casos en los que una simple break 2declaración concisa tendría mucho sentido. Además, refactor / returnno funciona de la misma manera continue. En estos casos, la interrupción numérica y la continuación serían más fáciles de seguir y menos complicadas que refactorizar a una función pequeña, generar excepciones o una lógica enrevesada que implica establecer una bandera para que se rompa en cada nivel de nido. Es una pena que Guido lo haya rechazado.
James Haigh

10
break; breaksería bueno.
PyRulez

55
@Jeyekomon El problema es que no necesita 3 o más bucles anidados para que esto sea un problema. 2 bucles anidados son bastante comunes
Jon

66
"El código tan complicado que requiere esta función es muy raro". Pero si alguna vez usa un código así de complicado, la falta de bucles etiquetados lo hará aún más complicado, ya que debe reenviar manualmente breaktodos los bucles. Estúpido.
BallpointBen

3
Aparentemente, solo puedo editar una publicación durante 5 minutos (han sido 6). Entonces, aquí está mi publicación editada: Mis 2 centavos: Perl ha etiquetado break (pero lo llama 'último') y 'next' para pasar directamente a la siguiente iteración. No es nada raro, lo uso todo el tiempo. Soy nuevo en Python y ya lo necesito. Además, los saltos numerados serían horribles para la refactorización: es mejor etiquetar el bucle del que desea salir, luego usar break <label> para indicar explícitamente de qué bucle desea salir.
John Deighan

119

Primero, la lógica ordinaria es útil.

Si, por alguna razón, las condiciones de terminación no se pueden resolver, las excepciones son un plan alternativo.

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

Para este ejemplo específico, una excepción puede no ser necesaria.

Por otro lado, a menudo tenemos las opciones "Y", "N" y "Q" en las aplicaciones en modo de caracteres. Para la opción "Q", queremos una salida inmediata. Eso es más excepcional.


44
En serio, las excepciones son extremadamente baratas y Python idiomático usa muchísimas. También es muy fácil definir y lanzar los personalizados.
Gregg Lind

13
Idea interesante. Tengo dudas sobre si amarlo u odiarlo.
Craig McQueen el

8
Esta solución sería más útil si mostrara las dos variaciones por separado. (1) usando una bandera ( done). (2) planteando una excepción. Fusionarlos en una sola solución solo hace que parezca complicado. Para futuros lectores: CUALQUIERA use todas las líneas que involucran done, O defina GetOutOfLoop(Exception)y aumente / excepto eso.
ToolmakerSteve

44
En general, el uso de try-blocks para cualquier otra cosa que no sean excepciones está muy mal visto. Los bloques de prueba están diseñados específicamente para el manejo de errores, y su uso para un flujo de control extraño no es muy bueno, estilísticamente.
nobillygreen

3
@ tommy.carstensen Eso no tiene sentido; tanto definir una nueva subclase de excepción como elevarla (como se muestra en la respuesta) y pasar un mensaje personalizado al Exceptionconstructor (por ejemplo raise Exception('bla bla bla')) son válidos tanto en Python 2 como en Python 3. La primera es preferible en este caso porque no queremos nuestro exceptbloque para capturar todas las excepciones, pero solo la excepción especial que estamos usando para salir del ciclo. Si hacemos las cosas como usted sugiere, y luego un error en nuestro código provoca una excepción inesperada, se tratará erróneamente de la misma manera que se sale deliberadamente del bucle.
Mark Amery el

54

Tiendo a estar de acuerdo en que la refactorización en una función suele ser el mejor enfoque para este tipo de situación, pero para cuando realmente necesita salir de los bucles anidados, aquí hay una variante interesante del enfoque de aumento de excepciones que describió @ S.Lott. Utiliza la withdeclaración de Python para hacer que el aumento de excepciones se vea un poco mejor. Defina un nuevo administrador de contexto (solo tiene que hacer esto una vez) con:

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

Ahora puede usar este administrador de contexto de la siguiente manera:

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"

Ventajas: (1) es un poco más limpio (sin bloque de prueba explícito), y (2) obtienes una Exceptionsubclase personalizada para cada uso de nested_break; No es necesario declarar su propia Exceptionsubclase cada vez.


40

Primero, también puede considerar hacer que el proceso de obtener y validar la entrada sea una función; dentro de esa función, puede devolver el valor si es correcto y seguir girando mientras tanto bucle si no. Esto esencialmente evita el problema que resolvió y, por lo general, puede aplicarse en el caso más general (ruptura de múltiples bucles). Si absolutamente debe mantener esta estructura en su código, y realmente no quiere tratar con booleanos de contabilidad ...

También puede usar goto de la siguiente manera (usando un módulo de April Fools desde aquí ):

#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

Lo sé, lo sé, "no usarás goto" y todo eso, pero funciona bien en casos extraños como este.


1
Si se parece al comando COME FROM en INTERCAL, entonces nada
1800 INFORMACIÓN

3
Me gusta el chiste, pero el objetivo del desbordamiento de pila es promover un buen código, así que tengo que rechazarlo :(
Christian Oudard

13
Creo que es una solución lo suficientemente limpia y legible para calificar como un buen código, así que lo voto. :)
JT Hurley

1
@JTHurley no, esto no es limpio y legible. Quiero decir, puede parecer que es limpio y legible en este ejemplo, pero en cualquier escenario de la vida real, ir a crear un desastre sagrado . (También esto es muuuy antipitónico ...)
Alois Mahdal

2
Goto tiene una mala reputación, en mi opinión, cualquier programador profesional debería poder manejarlo adecuadamente.
Albert Renshaw

33

Introduzca una nueva variable que usará como 'interruptor de bucle'. Primero asigne algo (False, 0, etc.), y luego, dentro del bucle externo, antes de romper, cambie el valor a otra cosa (True, 1, ...). Una vez que el ciclo sale, haga que el ciclo 'padre' verifique ese valor. Déjame demostrarte:

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

Si tiene un bucle infinito, esta es la única salida; para otros bucles, la ejecución es realmente mucho más rápida. Esto también funciona si tiene muchos bucles anidados. Puede salir de todo, o solo de unos pocos. ¡Posibilidades infinitas! Espero que esto haya ayudado!


22

Para salir de múltiples bucles anidados, sin refactorizar en una función, utilice una "instrucción goto simulada" con la excepción StopIteration incorporada :

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

except StopIteration: pass

Vea esta discusión sobre el uso de declaraciones goto para romper bucles anidados.


1
Esto se ve mucho mejor que crear su propia clase para manejar la excepción, y se ve muy limpio. ¿Hay alguna razón por la que no debería hacer esto?
mgjk

De hecho, StopIteration se usa para generadores, pero creo que normalmente no tiene ninguna excepción StopIteration no capturada. Parece una buena solución, pero de todos modos no hay ningún error al crear una nueva excepción.
Kowalski

1
La mejor y más simple solución para mí
Alexandre Huat

16

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

o algo así. Puede establecer una variable en el bucle interno y verificarla en el bucle externo inmediatamente después de que el bucle interno salga, rompiéndose si corresponde. Me gusta el método GOTO, siempre que no te importe usar un módulo de bromas de April Fool, no es Pythonic, pero tiene sentido.


Esta es una especie de configuración de la bandera!
SIslam

Creo que es una muy buena solución.
Kowalski

13

Esta no es la forma más bonita de hacerlo, pero en mi opinión, es la mejor manera.

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

Estoy bastante seguro de que también podrías resolver algo usando la recursividad, pero no sé si es una buena opción para ti.


Esta fue la solución correcta para mí. Mi caso de uso fue muy diferente al de los OP. Estaba recorriendo esencialmente los mismos datos dos veces para encontrar permutaciones, por lo que no quería separar los dos bucles while.
Brian Peterson,

9

¿Y por qué no seguir haciendo bucles si se cumplen dos condiciones? Creo que esta es una forma más pitónica:

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

¿No es así?

Todo lo mejor.


¿Por qué no solo while dejaVu:? Lo pones en verdad de todos modos.
Matthew Scharley el

hey que funciona! Estaba pensando en dos Truecondiciones omitir dos bucles, pero solo uno es suficiente.
Mauro Aspé

2
@MatthewScharley Creo que esto es para mostrar que esto funciona en bucles anidados.
manejar el

@ MauroAspé esto no hará exactamente lo que el OP solicita. seguirá ejecutando todo el bucle externo, pero el objetivo es que si se rompe el resto del código no se ejecutará
yamm

@yamm ¿Podría eso no resolverse con a if not dejaVu: breaken la parte inferior y así salir del bucle principal? Creo que la solución está más cerca de lo que se preguntó. +1
milcak

8

Factorice su lógica de bucle en un iterador que produzca las variables de bucle y regrese cuando haya terminado: aquí hay una simple que presenta imágenes en filas / columnas hasta que nos quedemos sin imágenes o sin lugares para colocarlas:

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

Esto tiene la ventaja de dividir la complicada lógica de bucle y el procesamiento ...


3

En este caso, como también lo señalaron otros, la descomposición funcional es el camino a seguir. Código en 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

3

Hay un truco oculto en la while ... elseestructura de Python que se puede usar para simular el doble salto sin muchos cambios / adiciones de código. En esencia, si la whilecondición es falsa, elsese activa el bloque. Ni excepciones, continueni breakactivan el elsebloqueo. Para obtener más información, consulte las respuestas a la " Cláusula Else en Python while ", o 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

El único inconveniente es que necesita mover la condición de doble ruptura a la whilecondición (o agregar una variable de bandera). Existen variaciones de esto también para el forciclo, donde el elsebloque se activa después de la finalización del ciclo.


Esto no parece cumplir con el requisito de pausas dobles. Funciona para el problema exacto dado, pero no para la pregunta real.
Dakkaron

@Dakkaron ¿Estás seguro de haber entendido el código correctamente? De hecho, el código resuelve la pregunta de los OP y se rompe de manera similar a la solicitud. Sin embargo, no se rompe de múltiples bucles, pero usa la cláusula else para reemplazar la necesidad de duplicar la ruptura.
holroy

Según tengo entendido, la pregunta era How to break out of multiple loops in Python?y la respuesta debería haber sido "No funciona, intente otra cosa". Sé que corrige el ejemplo exacto del OP, pero no responde a su pregunta.
Dakkaron

@Dakkaron, vea la declaración del problema bajo el código y, en mi opinión, sí responde a la pregunta de los OP.
holroy

2

Otra forma de reducir su iteración a un ciclo de un solo nivel sería mediante el uso de generadores como también se especifica en la referencia de Python

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

Puede ampliarlo a cualquier número de niveles para el bucle

La desventaja es que ya no puedes romper un solo nivel. Es todo o nada.

Otro inconveniente es que no funciona con un ciclo while. Originalmente quería publicar esta respuesta en Python: `romper` de todos los bucles, pero desafortunadamente eso está cerrado como un duplicado de este


1
También funciona para los bucles while, solo necesita escribir su generador como def (con rendimiento), no como comprensión.
Veky

Sí, un orador en un PyCon afirma aquí que incluso la respuesta aceptada de @ RobertRossney no es realmente Pythonic, pero un generador es la forma correcta de romper múltiples bucles. (¡Recomiendo ver el video completo!)
Post169

2

Mi razón para venir aquí es que tenía un bucle externo y un bucle interno así:

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

Como puede ver, en realidad no irá a la próxima x, sino a la siguiente y.

Lo que encontré para resolver esto simplemente fue ejecutar la matriz dos veces:

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

Sé que este fue un caso específico de la pregunta de OP, pero lo estoy publicando con la esperanza de que ayude a alguien a pensar en su problema de manera diferente mientras mantiene las cosas simples.


Probablemente no sea Python. ¿Cuál es el tipo de matriz? Probablemente lista, pero ¿qué contiene? Incluso si contiene ints, array.pop (x) probablemente no hará lo que desea.
Veky

Ese es un buen punto. No puedo encontrar el código al que hice referencia. Para cualquiera que lea esto, array.pop (i) "Elimina el elemento con el índice i de la matriz y lo devuelve". según la documentación de python. Por lo tanto, sería necesario obtener el índice del elemento x en la matriz para que este código funcione como se esperaba. También existe la función array.remove (x) que haría lo que se espera. Modificaré mi respuesta anterior para corregir ese error. Esto supone que la segunda matriz no contiene duplicados, ya que array.remove (x) solo eliminará la primera instancia de x encontrada.
Nathan Garabedian

Ok, entonces lo entiendo. En ese caso, simplemente usar en breaklugar de continueharía lo que quieres, ¿no? :-)
Veky

Sí, por razones de eficiencia y claridad, es probable que desee usar break en lugar de continuar en estos ejemplos. :)
Nathan Garabedian

2

Intenta usar un generador infinito.

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

2

Al usar una función:

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()

Intente ejecutar los códigos anteriores comentando el return .

Sin usar ninguna función:

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

Ahora, ejecute los códigos anteriores tal como están primero y luego intente ejecutar comentando cada línea que contiene breakuna a la vez desde la parte inferior.


2

Una manera fácil de convertir múltiples bucles en un solo bucle rompible es usar 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!

Debe indexar sus objetos, en lugar de poder recorrer los valores explícitamente, pero al menos en casos simples parece ser aproximadamente 2-20 veces más simple que la mayoría de las respuestas sugeridas.


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

1

probablemente un pequeño truco como el que se muestra a continuación servirá si no prefiere volver a la función

Se agregó 1 variable break_level para controlar la condición del bucle while

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

1

Puede definir una variable (por ejemplo, break_statement ), luego cambiarla a un valor diferente cuando se produce la condición de dos rupturas y usarla en la instrucción if para romper también desde el segundo bucle.

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

Buen punto, sin embargo, en cada uno de los niveles por encima de nuestro nivel interno de interés necesitaríamos escanear esa variable. Se siente realmente mal que el lenguaje no tenga una instrucción GoTo, en cuanto al rendimiento.
Anatoly Alekseev

1

Me gustaría recordarle que las funciones en Python se pueden crear justo en el medio del código y pueden acceder a las variables circundantes de forma transparente para leer y con nonlocaloglobal declaración por escrito.

Por lo tanto, puede usar una función como una "estructura de control rompible", que define un lugar al que desea regresar:

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

1

Soluciones de 2 maneras

Con un ejemplo: ¿Son estas dos matrices iguales / iguales?
matriz1 y matriz2 son del mismo tamaño, n, 2 matrices dimensionales.

Primera solución , sin función

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

Segunda solución , con una función
Esta es la solución final para mi caso

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

¡Que tengas un buen día!


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

0

Esperemos que esto ayude:

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

0

Aquí hay una implementación que parece funcionar:

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)

El único inconveniente es que debe definir break_antes de los bucles.


0

No hay forma de hacerlo desde un nivel de idioma. Algunos idiomas tienen un goto, otros tienen un descanso que requiere una discusión, Python no.

Las mejores opciones son:

  1. Establezca un indicador que sea verificado por el bucle externo, o establezca la condición de los bucles externos.

  2. Ponga el bucle en una función y use el retorno para romper todos los bucles a la vez.

  3. Reformula tu lógica.

El crédito es para Vivek Nagarajan, programador desde 1987


Usando la función

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

Usando bandera

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

-3

Similar al anterior, pero más compacto. (Los booleanos son solo números)

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   # <--- !

2
Esto se ve bastante feo y hace que el código sea más difícil de entender, en comparación con el anterior. Además, está mal. Se pierde la comprobación de si la entrada es aceptable y se rompe después de 1 ciclo.
Eric

-3

Dado que esta pregunta se ha convertido en una pregunta estándar para entrar en un ciclo particular, me gustaría dar mi respuesta con un ejemplo usando Exception .

Aunque no existe una etiqueta llamada ruptura del bucle en la construcción de bucle multipally, podemos hacer uso de Excepciones definidas por el usuario para dividirnos en un bucle particular de nuestra elección. Considere el siguiente ejemplo donde imprimamos todos los números de hasta 4 dígitos en el sistema de numeración de base 6:

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

Cuando imprimimos la salida, nunca obtendremos ningún valor cuyo lugar de unidad sea 4. En ese caso, no saldremos de ningún bucle cuando BreakLoop(4)se eleva y se atrapa en el mismo bucle. Del mismo modo, cada vez que diez lugares tienen 3, nos dividimos en el tercer bucle usando BreakLoop(3). Cada vez que cien lugares tienen 5, nos BreakLoop(2)separamos en el segundo bucle usando y cuando el mil lugar tiene 2, nos separamos en el primer bucle usando BreakLoop(1).

En resumen, aumente su Excepción (incorporada o definida por el usuario) en los bucles internos, y recójala en el bucle desde donde desea reanudar su control. Si desea romper todos los bucles, tome la excepción fuera de todos los bucles. (No he mostrado este caso en el ejemplo).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.