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

z trzeciej pętli Jak wyjść z pętli prądowej i przejść do następnej wartości for row in b:?python: wyjście z dwóch pętli

+0

Prawdopodobnie chciałbym owijać ten blok próbując go wyrwać z podbiciem. –

+0

proszę, pokaż mi, w jaki sposób –

+0

Czy mogę zapytać, jaki stan w wewnętrznej pętli wymusi "przerwę"? –

Odpowiedz

22

Ten wykorzystuje logiczną, aby sprawdzić, czy są jeszcze zrobione:

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

    if done: 
     break 

ten będzie continue jeśli przerwa nie był używany. else zostanie pominięty, jeśli nastąpiła przerwa, więc zobaczy następny break. Takie podejście ma tę zaletę, że nie trzeba używać zmiennej, ale niektórym może być trudniej ją odczytać.

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

    break 
+0

Cóż, miał trzy pętle, a nie dwie. –

+1

Cóż, pomyślałem, że być może OP może być w stanie ekstrapolować do trzech pętli. –

+2

@Teodor: przeczytaj q. ostrożnie - najbardziej zewnętrzna pętla nie musi być wychodząca, więc przykładowa pętla w/2 jest słuszna, dobry komentarz –

2

Nietestowane:

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 nie posiada strukturę sterowania za złamanie z dwóch pętli na raz, więc trzeba zrobić coś takiego podręcznika.

+0

@cjrh: Jestem ciekawy: dlaczego miałbyś pisać "Świetna odpowiedź "ale nie głosuj w górę odpowiedzi? Bez presji ... –

+1

Czy widzisz moją odpowiedź? –

+0

Ah, teraz rozumiem! :) –

6

Jeśli masz trzy poziomy pętli w jednej metodzie, prawdopodobnie będziesz musiał ponownie przemyśleć swój projekt.

  • Podziel swoją metodę na mniejsze, prostsze metody.
  • Skorzystaj ze zrozumienia list i metod takich jak all i any, aby uniknąć pisania jawnych pętli.

Wykonanie jednego z nich powinno oznaczać, że problem nie występuje.

+1

Nie jestem pewien, czy się z tym zgadzam, szczególnie w przypadku iteracji złożonej struktury danych. Czasami masz słowniki w słownikach w słownikach! – katrielalex

+0

@karielalex: Nie zgadzasz się z tymi dwoma punktami, czy tylko z drugim? –

+0

"Jeśli masz trzy poziomy pętli w jednej metodzie, prawdopodobnie musisz przemyśleć swój projekt." Myślę, że jest różnica między przypadkiem iteracji nad strukturą danych - w takim przypadku wielokrotna iteracja jest semantycznie jedną sekcją i nie należy jej rozdzielać ani przycinać - i przypadkiem, gdy zbyt wiele robi się w jednym miejscu . W tej ostatniej sytuacji zgadzam się z obydwoma punktami. Na przykład ostatnio zbudowałem DFA, który miał tabelę przejściową 'initial node' ->' arc type' -> 'guard' ->' final node'. Do iteracji na wszystkich krawędziach potrzebne są trzy pętle! – 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, jak sugeruje w komentarzu @ gddc, znajduje się jedna z możliwości. Innym jest do „zawijania” dwa do jednego zagnieżdżonej pętli:

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

Teraz, break z for brand zagnieżdżonej pętli powróci do poziomu zewnętrznej pętli for row. Oczywiście działa to tylko wtedy, gdy kod, który jest tutaj zastąpiony przez ..., nie musi widzieć nazwy drug związanej z badanym lekiem. Czy tak właśnie jest w twoim przypadku?

+0

Wystarczająco prosty, aby uzyskać nazwa leku jest wymagana. 'dla marki, leku w ((b, d) dla d in drug_input dla b w brand_namames [d]):' –

4

Chciałbym rozważyć umieszczenie dwóch wewnętrznych pętli w funkcji i użycie stamtąd powrotu. Prawdopodobnie przemyślenie tego, co robisz i jak daje lepszą alternatywę do tego.

Czy możesz podać swój aktualny pseudo kod, dane wejściowe i wyjściowe, abyśmy mogli usunąć potrzebę przerwania na pierwszym miejscu? Musimy zobaczyć, gdzie zmienne pętli są używane lub jeszcze lepiej, jaki jest cel przetwarzania.

6

obsługa wyjątków uderzeń ustawienie zmiennych wszędzie 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

Wyjątki są tylko w wyjątkowych sytuacjach! –

+1

"To pochodzi od wyjątku, a nie od standardowego błędu, ponieważ nie jest uważane za błąd w jego normalnej aplikacji." http://docs.python.org/library/exceptions.html#exceptions.StopIteration – brianz

+1

OK, to był całkiem dobry powrót :) Ale poważnie, nie obsługuj wyjątków dla przepływu sterowania. W dowolnym języku. Funkcja próbna z wyjątkiem jest bardzo, bardzo rozpowszechnionym wizualnym sygnałem, że "wydarzyło się coś niezwykłego". –

4

Najnowsze PEP widzę zainteresowanie tej funkcji jest 3136 (i została odrzucona): http://mail.python.org/pipermail/python-3000/2007-July/008663.html

Sąsiednie & najczystszych co mogę zobaczyć, co chcesz zrobić, to wykonać następujące czynności (a ponieważ nawet nazwy typów mają zasięg, możesz zadeklarować LocalBreak w funkcji, której potrzebuje):

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 obsługuje oświadczenia for...else. else blok jest oceniany, jeśli wewnętrzny break nie został uruchomiony.

+1

Przepraszam, czy możesz mi powiedzieć, proszę, co to dodaje do aktualnej treści? –

2

Jeśli masz zbyt wiele osadzonych pętli, może to być czas na refaktor. W tym przypadku uważam, że najlepszym refaktorem jest przeniesienie twoich pętli do funkcji i użycie instrukcji return. To wymusi wyjście z dowolnej liczby pętli. Na przykład:

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 

Teraz, być może zmieniając logika jak to jest trudne, ale założę refaktoring pomoże w inny sposób.

Powiązane problemy