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

dal terzo ciclo come si esce dal loop corrente e si passa al valore successivo di for row in b:?python: uscita da due anelli

+0

Probabilmente avrei avvolto questo blocco in una prova e uscirne con un rilancio. –

+0

per favore mostrami come –

+0

Posso chiedere quale condizione nel loop interno forzerebbe un 'break'? –

risposta

22

Questo si usa un valore booleano per vedere se si è fatto ancora:

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

    if done: 
     break 

questo sarà continue se è stata utilizzata nessuna rottura. Lo else verrà saltato se ci fosse un'interruzione, quindi vedrà il prossimo break. Questo approccio ha il vantaggio di non dover usare una variabile, ma potrebbe essere più difficile da leggere per alcuni.

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

    break 
+0

Bene, aveva tre anelli, non due. –

+1

Bene, ho pensato che forse OP potrebbe essere in grado di estrapolare a tre cicli. –

+2

@ Teodor: leggi q. attentamente - il ciclo più esterno non ha bisogno di essere chiuso, quindi esempio w/2 loops è la cosa giusta –

2

testato:

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 non ha una struttura di controllo per la rottura da due anelli in una sola volta, quindi è necessario fare manuale di qualcosa di simile.

+0

@cjrh: Sono curioso: perché scriveresti "Grande risposta "ma non votare la risposta? Nessuna pressione ... –

+1

Hai visto la mia risposta? –

+0

Ah, ora capisco! :) –

6

Se si dispone di tre livelli di looping in un metodo, è probabilmente necessario ripensare il proprio progetto.

  • Dividere il metodo in metodi più piccoli e più semplici.
  • Utilizzare una comprensione di lista e metodi come all e any per evitare di scrivere cicli espliciti.

Fare uno di questi dovrebbe significare che non si ha più questo problema.

+1

Non sono sicuro di essere d'accordo, specialmente nel caso di iterazione su una complessa struttura di dati. A volte hai solo dizionari nei dizionari nei dizionari! – katrielalex

+0

@karielalex: Non sei d'accordo con entrambi i punti, o solo con il secondo? –

+0

Con "Se si dispone di tre livelli di looping in un metodo, è probabile che sia necessario ripensare il proprio design." Penso che ci sia una differenza tra il caso di iterare su una struttura dati - nel qual caso l'iterazione multipla è semanticamente una sezione e non dovrebbe essere necessario dividere o sfoltire - e il caso in cui viene fatto troppo in un unico posto . In quest'ultima situazione sono d'accordo con entrambi i punti. Ad esempio, di recente ho creato un DFA che aveva un 'nodo iniziale' '->' arc type' della tabella di transizione -> 'guard' ->' nodo finale'. Per scorrere su tutti i bordi hai bisogno di tre anelli! – 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, come suggerito nel commento di @ Dgcs, è una possibilità. Un altro è quello di "avvolgere" i due cicli annidati in uno:

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

ora, un break dal for brand ciclo nidificato tornerà al livello di ciclo esterno for row. Naturalmente, questo funziona solo quando il codice che è qui sostituito da ... non ha bisogno di vedere il nome drug associato al farmaco attualmente in esame. E 'questo il tuo caso?

+0

Abbastanza semplice da ottenere nome del farmaco è richiesto. 'per marca, farmaco in ((b, d) per d in drug_input per b in brand_names [d]):' –

4

riterrei mettere a due cicli interni in funzione e utilizzando ritorno da lì. Probabilmente ripensare a quello che stai facendo e come dare la migliore alternativa a questo però.

Potresti fornire il tuo attuale pseudo-codice, input e output, in modo che potremmo provare a rimuovere la necessità della pausa al primo posto? Abbiamo bisogno di vedere dove le variabili del ciclo sono usate o meglio ancora, qual è l'obiettivo dell'elaborazione.

6

battiti gestione delle eccezioni impostazione variabili in tutto il luogo IMO

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

Le eccezioni sono solo per situazioni eccezionali! –

+1

"Questo è derivato da Exception piuttosto che da StandardError, poiché questo non è considerato un errore nella sua normale applicazione." http://docs.python.org/library/exceptions.html#exceptions.StopIteration – brianz

+1

Ok, è stato un buon ritorno :) Ma seriamente, non gestire le eccezioni per il controllo del flusso. In qualsiasi lingua Un conduttore try-except è uno spunto visivo molto, molto diffuso per "qualcosa di insolito è appena successo". –

4

Ultime PEP Vedo che richiede questa funzione è 3136 (ed è stata respinta): http://mail.python.org/pipermail/python-3000/2007-July/008663.html

più vicino & cosa più pulito che poteva vedere fino a che dovresti fare quanto segue (e visto che anche i nomi dei tipi sono ambiti, potresti dichiarare LocalBreak all'interno della funzione necessaria):

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 supporta le istruzioni for...else. Il blocco else viene valutato se l'interno break non viene attivato.

+1

scusa, puoi dirmi per favore cosa aggiunge questo al contenuto attuale? –

2

Se si dispone di troppi loop incorporati, potrebbe essere il momento per un refactoring. In questo caso, ritengo che il miglior refactor sia quello di spostare i loop in una funzione e utilizzare una dichiarazione return. Questo forzerà l'uscita da qualsiasi numero di loop. Per esempio:

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 

Ora, forse riformulare la logica come questo è difficile, ma scommetto che il refactoring aiuterà in altri modi.