2010-07-28 36 views
24
for row in b: 
    for drug in drug_input: 
     for brand in brand_names[drug]: 

desde el tercer bucle ¿cómo salgo del bucle actual y voy al siguiente valor de for row in b:?python: salir de dos bucles

+0

Probablemente envolvería este bloque en un intento y me largaría con un aumento. –

+0

por favor muéstrame cómo –

+0

¿Puedo preguntar qué condición en el lazo interno forzaría un 'break'? –

Respuesta

22

Ésta utiliza un booleano para ver si ha terminado aún:

done = False 
for x in xs: 
    for y in ys: 
     if bad: 
      done = True 
      break 

    if done: 
     break 

Esto lo hará continue si no se utilizó descanso. El else se omitirá si hubo un corte, por lo que verá el siguiente break. Este enfoque tiene el beneficio de no tener que usar una variable, pero puede ser más difícil de leer para algunos.

for x in xs: 
    for y in ys: 
     if bad: 
      break 
    else: 
     continue 

    break 
+0

Bueno, tenía tres bucles, no dos. –

+1

Bueno, pensé que quizás OP podría extrapolar a tres bucles. –

+2

@Teodor: leer q. con cuidado: el bucle más externo no necesita salir, por lo que el ejemplo w/2 loops es lo correcto –

2

No comprobado:

inner_termination=False 
for row in b: 
    for drug in drug_input: 
     for brand in brand_names[drug]: 
      <blah> 
      if break_condition: 
       inner_termination=True 
       break 
      <blah> 
     if inner_termination: 
      inner_termination=False 
      break 
7
for row in b: 
    more_drugs = True 
    for drug in drug_input: 
     for brand in brand_names[drug]: 
      if something: 
       more_drugs = False 
       break 

     if not more_drugs: 
      break 

Python no tiene una estructura de control para romper a partir de dos bucles a la vez, por lo que hay que hacer algo manual de este modo.

+0

@cjrh: Tengo curiosidad: ¿por qué escribiría "Gran respuesta "pero no vota la respuesta? Sin presión ... –

+1

¿Has visto mi respuesta? –

+0

¡Ah, ahora lo entiendo! :) –

6

Si tiene tres niveles de bucle en un método, probablemente necesite replantear su diseño.

  • Divida su método en métodos más pequeños y sencillos.
  • Use una lista de comprensión y métodos como all y any para evitar escribir bucles explícitos.

Hacer cualquiera de estos debe significar que ya no tiene este problema.

+1

No estoy seguro de estar de acuerdo con eso, específicamente en el caso de la iteración sobre una estructura de datos compleja. ¡A veces solo tienes diccionarios en diccionarios en diccionarios! – katrielalex

+0

@karielalex: ¿No estás de acuerdo con los dos puntos, o solo con el segundo? –

+0

Con "Si tienes tres niveles de bucle en un método, entonces probablemente necesites replantear tu diseño". Creo que hay una diferencia entre el caso de iterar sobre una estructura de datos, en cuyo caso la iteración múltiple es semánticamente una sección y no debería dividirse o eliminarse, y el caso donde se hace demasiado en un solo lugar . En la última situación, estoy de acuerdo con ambos puntos. Por ejemplo, recientemente construí un DFA que tenía una tabla de transición 'initial node' ->' arc type' -> 'guard' ->' node final'. Para iterar sobre todos los bordes, necesitas tres bucles. – katrielalex

2
for row in b: 
    ok = True 
    for drug in drug_input: 
     if not ok: 
      break; 
     for brand in brand_names[drug]: 
      if not ok: 
       break 
      if whatever: 
       ok = False 
2

try/except/raise, como se sugiere en el comentario de @ GDDC, es una posibilidad. Otra es "envolver" los dos bucles anidados en una sola:

for row in b: 
    for brand in (b for d in drug_input for b in brand_names[d]): 
    ... 

ahora, un breakfor brand del bucle anidado irá de nuevo al nivel del bucle externo for row. Por supuesto, esto solo funciona cuando el código que aquí se reemplaza por ... no necesita ver el nombre drug vinculado al medicamento que se está examinando actualmente. ¿Es ese el caso para ti?

+0

Lo suficientemente simple para obtener el nombre del medicamento es obligatorio. 'para marca, droga en ((b, d) para d en drug_input para b en brand_names [d]):' –

4

Consideraría poner dos bucles interiores en la función y usando devolver desde allí. Probablemente, reconsiderar lo que estás haciendo y cómo se da la mejor alternativa a eso.

¿Podría dar su pseudo código actual, entrada y salida, para que podamos tratar de eliminar la necesidad del descanso en primer lugar? Necesitamos ver dónde se utilizan las variables de bucle o, mejor aún, cuál es el objetivo del procesamiento.

6

latidos manejo de excepciones establecer variables de todo el lugar de la OMI

for row in b: 
    for drug in drug_input: 
     try: 
      for brand in brand_names[drug]: 
       if some_condition: 
        raise StopIteration 
     except StopIteration: 
      break 
+0

¡Las excepciones son solo para situaciones excepcionales! –

+1

"Esto se deriva de Exception en lugar de StandardError, ya que esto no se considera un error en su aplicación normal." http://docs.python.org/library/exceptions.html#exceptions.StopIteration – brianz

+1

Ok, eso fue un regreso bastante bueno :) Pero en serio, no maneje excepciones para el flujo de control. En cualquier idioma. Un controlador try-except es una señal visual muy, muy extendida para "algo inusual que acaba de suceder". –

4

reciente PEP veo que solicita esta característica es de 3136 (y fue rechazada): http://mail.python.org/pipermail/python-3000/2007-July/008663.html

más cercano & lo más limpio que podía ver a lo lo que quiere hacer sería hacer lo siguiente (y dado que incluso los nombres de tipo tienen un alcance, puede declarar LocalBreak dentro de la función que necesita):

class LocalBreak(Exception): pass 

try: 
    for i in ...: 
     for h in ...: 
      for j in ...: 
       if should_break(j): 
       raise LocalBreak() 
except LocalBreak: 
    pass 
2
for a in aa: 
    for b in bb: 
     for c in cc: 
      if c == a[b]: 
       break 
     else: 
      continue 
     break 

Python admite for...else declaraciones. El bloque else se evalúa si el break interno no se activa.

+1

lo siento, ¿puedes decirme qué añade esto al contenido actual? –

2

Si tiene demasiados bucles incrustados, podría ser el momento de un refactor. En este caso, creo que el mejor refactor es mover sus bucles en una función y usar una declaración return. Eso forzará la salida de cualquier cantidad de bucles. Por ejemplo:

def example(self, drug_input): 
    ok = False 
    for x in drug_input["names"]: 
     for y in range(drug_input["number_of_drugs"]): 
      for z in drug_input["list_of_drugs"]: 
       # do stuff 
       if ok: 
        return drug_costs 

Ahora, tal vez reformulando su lógica de este tipo es complicado, pero apuesto a la refactorización será ayudar de otras maneras.

Cuestiones relacionadas