¿Cómo puedo salir de múltiples bucles?
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 y luego otra verificación más limitada en el bucle exterior para salir todos juntos si el usuario está satisfecho?
Mi primer instinto sería refactorizar el bucle anidado en una función y usarlo return
para salir.
Aquí hay otro enfoque que es breve. La desventaja es que sólo puedes romper el bucle exterior, 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 utiliza la construcción for/else explicada en: ¿ Por qué Python usa 'else' después de los bucles for y while?
Idea clave: Parece que el bucle exterior siempre se rompe. Pero si el bucle interior no se rompe, el bucle exterior tampoco lo hará.
La continue
declaració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 continue
se evita hábilmente la rotura exterior.
PEP 3136 propone la etiqueta pausa/continuar. Guido lo rechazó porque "un código tan complicado que requiera esta característica es muy raro". Sin embargo, el PEP menciona algunas soluciones (como la técnica de excepción), mientras que Guido cree que refactorizar para usar return será más sencillo en la mayoría de los casos.
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, es posible que no sea necesaria una excepción.
Por otro lado, muchas veces tenemos las opciones "Y", "N" y "Q" en las aplicaciones en modo caracteres. Para la opción "Q", queremos una salida inmediata. Eso es más excepcional.