Python: Continuando a la siguiente iteración en el bucle externo

Quería saber si hay alguna forma integrada de continuar con la siguiente iteración en el bucle externo en python. Por ejemplo, considere el código:

for ii in range(200): for jj in range(200, 400): ...block0... if something: continue ...block1... 

Quiero que esta instrucción continue salga del bucle jj y pase al siguiente elemento en el bucle ii. Puedo implementar esta lógica de alguna otra manera (estableciendo una variable de marca), pero ¿hay una manera fácil de hacer esto o es como pedir demasiado?

 for i in ...: for j in ...: for k in ...: if something: # continue loop i 

En un caso general, cuando tiene varios niveles de bucle y la break no funciona para usted (porque desea continuar uno de los bucles superiores, no el que está justo arriba del actual), puede hacer uno de los siguientes

Refactoriza los bucles de los que quieres escapar en una función

 def inner(): for j in ...: for k in ...: if something: return for i in ...: inner() 

La desventaja es que es posible que deba pasar a esa nueva función algunas variables, que anteriormente estaban dentro del scope. Puede simplemente pasarlos como parámetros, convertirlos en variables de instancia en un objeto (crear un nuevo objeto solo para esta función, si tiene sentido), o variables globales, singletons, lo que sea (ehm, ehm).

O puede definir inner como una función anidada y dejar que solo capture lo que necesita (¿puede ser más lento?)

 for i in ...: def inner(): for j in ...: for k in ...: if something: return inner() 

Usar excepciones

Filosóficamente, esto es para lo que están las excepciones, rompiendo el flujo del progtwig a través de los bloques de construcción de progtwigción estructurada (if, for, while) cuando sea necesario.

La ventaja es que no tiene que dividir la única pieza de código en varias partes. Esto es bueno si es algún tipo de cálculo que estás diseñando mientras lo escribes en Python. La introducción de abstracciones en este punto temprano puede ralentizarlo.

Lo malo de este enfoque es que los autores de los intérpretes / comstackdores generalmente asumen que las excepciones son excepcionales y se optimizan para ellas en consecuencia.

 class ContinueI(Exception): pass continue_i = ContinueI() for i in ...: try: for j in ...: for k in ...: if something: raise continue_i except ContinueI: continue 

Crea una clase de excepción especial para esto, de modo que no te arriesgues a silenciar accidentalmente alguna otra excepción.

Algo completamente distinto

Estoy seguro de que todavía hay otras soluciones.

 for ii in range(200): for jj in range(200, 400): ...block0... if something: break else: ...block1... 

Break romperá el bucle interno, y el bloque1 no se ejecutará (se ejecutará solo si el bucle interno se sale normalmente).

En otros idiomas puede etiquetar el bucle y romper el bucle etiquetado. La Propuesta de mejora de Python (PEP) 3136 sugirió agregar estos a Python, pero Guido lo rechazó :

Sin embargo, lo rechazo sobre la base de que el código tan complicado para requerir esta función es muy raro. En la mayoría de los casos, existen soluciones alternativas que producen códigos limpios, por ejemplo, usando ‘retorno’. Si bien estoy seguro de que hay algunos casos reales (raros) en los que la claridad del código se vería afectada por una refactorización que hace posible utilizar el retorno, esto se compensa con dos problemas:

  1. La complejidad añadida al lenguaje, de forma permanente. Esto afecta no solo a todas las implementaciones de Python, sino también a todas las herramientas de análisis de fonts, además de toda la documentación del idioma.

  2. Mi expectativa de que la característica se usará más de lo que se usará correctamente, lo que lleva a una disminución neta en la claridad del código (medida en todo el código de Python escrito a partir de ahora). Los progtwigdores perezosos están en todas partes, y antes de que te des cuenta, tienes un increíble desastre en tus manos de código ininteligible.

Entonces, si eso es lo que esperabas, estás fuera de suerte, pero mira una de las otras respuestas ya que hay buenas opciones allí.

Creo que podrías hacer algo como esto:

 for ii in range(200): restart = False for jj in range(200, 400): ...block0... if something: restart = True break if restart: continue ...block1... 

Otra forma de resolver este tipo de problema es usar Exception ().

 for ii in range(200): try: for jj in range(200, 400): ...block0... if something: raise Exception() except Exception: continue ...block1... 

Por ejemplo:

 for n in range(1,4): for m in range(1,4): print n,'-',m 

resultado:

  1-1 1-2 1-3 2-1 2-2 2-3 3-1 3-2 3-3 

Suponiendo que queremos saltar al bucle n externo desde m loop si m = 3:

 for n in range(1,4): try: for m in range(1,4): if m == 3: raise Exception() print n,'-',m except Exception: continue 

resultado:

  1-1 1-2 2-1 2-2 3-1 3-2 

Enlace de referencia: http://www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python

Creo que una de las maneras más fáciles de lograr esto es reemplazar la statement “continuar” por “romper”, es decir,

 for ii in range(200): for jj in range(200, 400): ...block0... if something: break ...block1... 

Por ejemplo, aquí está el código fácil para ver cómo funciona exactamente:

 for i in range(10): print("doing outer loop") print("i=",i) for p in range(10): print("doing inner loop") print("p=",p) if p==3: print("breaking from inner loop") break print("doing some code in outer loop") 

Queremos encontrar algo y luego detener la iteración interna. Yo uso un sistema de bandera.

 for l in f: flag = True for e in r: if flag==False:continue if somecondition: do_something() flag=False 

Acabo de hacer algo como esto. Mi solución para esto fue reemplazar el interior por bucle con una lista de comprensión.

 for ii in range(200): done = any([op(ii, jj) for jj in range(200, 400)]) ...block0... if done: continue ...block1... 

donde op es un operador booleano que actúa sobre una combinación de ii y jj. En mi caso, si alguna de las operaciones se volvía verdadera, había terminado.

Esto realmente no es tan diferente de dividir el código en una función, pero pensé que usar el operador “any” para hacer un OR lógico en una lista de booleanos y hacer la lógica todo en una línea era interesante. También evita la llamada a la función.