2009-03-17 13 views
175

Powiel możliwe:
How to break out of multiple loops in Python?wyrwanie się z zagnieżdżonych pętli

Czy istnieje prostszy sposób, aby wyrwać się z pętli zagnieżdżonych niż rzuca wyjątek? (W Perl, można dać etykiet do każdej pętli i co najmniej kontynuować zewnętrzną pętlę.)

for x in range(10): 
    for y in range(10): 
     print x*y 
     if x*y > 50: 
      "break both loops" 

Ie, czy jest ładniejszy sposób niż:

class BreakIt(Exception): pass 

try: 
    for x in range(10): 
     for y in range(10): 
      print x*y 
      if x*y > 50: 
       raise BreakIt 
except BreakIt: 
    pass 

Odpowiedz

99

To przynajmniej sugerowano, ale także rejected. Nie sądzę, żeby był inny sposób, niż powtarzanie testu lub ponowna organizacja kodu. Czasami jest to trochę denerwujące.

W numerze rejection message pan poseł van Rossum wspomina o użyciu numeru return, który jest bardzo rozsądny i powinien być zapamiętany osobiście. :)

+9

Po drugie używam instrukcji 'return'. Zmusiło mnie to do napisania wewnętrznej pętli w drugiej funkcji, ale znacznie ułatwiło zrozumienie kodu. – vdboor

+0

To ogólne rozwiązanie, które działa również, gdy po zagnieżdżonej pętli for następują inne instrukcje. Na przykład. podczas pętli nad listą zdań i użycia kilku pętli do odfiltrowania określonych zdań w oparciu o istnienie określonych słów lub liczb, przed wykonaniem rzeczywistej pracy na końcu zewnętrznej pętli for. – Anthon

+7

Rozwiązanie pana van Rossuma nie działa, gdy znajdujemy się w generatorze, co jest dość dużą dziurą IMHO –

3

W tym konkretnym przypadku można połączyć pętle z nowoczesnym pythonem (3.0 i prawdopodobnie 2.6) za pomocą itertools.product.

Ja sam wziąłem to za pewną regułę, jeśli zagnieżdżymy zbyt wiele pętli (jak w więcej niż 2), zazwyczaj można wyodrębnić jedną z pętli w inny sposób lub połączyć pętle w jedną , tak jak w tym przypadku.

8

Można również zmienić kod, aby użyć generatora. Ale może to nie być rozwiązanie dla wszystkich typów zagnieżdżonych pętli.

476
for x in xrange(10): 
    for y in xrange(10): 
     print x*y 
     if x*y > 50: 
      break 
    else: 
     continue # executed if the loop ended normally (no break) 
    break # executed if 'continue' was skipped (break) 

Te same prace dla głębszych pętli:

for x in xrange(10): 
    for y in xrange(10): 
     for z in xrange(10): 
      print x,y,z 
      if x*y*z == 30: 
       break 
     else: 
      continue 
     break 
    else: 
     continue 
    break 
+14

Aby uzyskać wyjaśnienie na ten temat: http://psung.blogspot.com.au/2007/12/for-else- in-python.html – aiham

+6

Ze względu na wymaganą instrukcję continue dla zewnętrznej pętli, zazwyczaj nie działa dobrze w sytuacjach, w których zagnieżdżona pętla nie jest jedynym kodem w zewnętrznej pętli for. Przykład OP może być zbyt prosty. – Anthon

+5

Możesz zamienić 'continue' na" ok = True', a 'break' z' if not ok: break'. –

52

Jeśli jesteś w stanie wyodrębnić kod pętli do funkcji, o return Oświadczenie może być stosowane, aby wyjść z zewnętrzną pętlę w dowolnym momencie.

def foo(): 
    for x in range(10): 
     for y in range(10): 
      print x*y 
      if x*y > 50: 
       return 
foo() 

Jeśli trudno wyodrębnić tę funkcję można użyć wewnętrznej funkcji, jak sugeruje @ bjd2385, np

def your_outer_func(): 
    ... 
    def inner_func(): 
     for x in range(10): 
      for y in range(10): 
       print x*y 
       if x*y > 50: 
        return 
    inner_func() 
    ... 
+1

Moglibyśmy użyć funkcji zagnieżdżonej w tym przypadku ... – bjd2385

+1

@ bjd2385 dobry punkt, zaktualizowany post z zagnieżdżonym func –

18

Czasami używam zmiennej binarnej. Naiwny, jeśli chcesz, ale uważam, że jest dość elastyczny i wygodny do czytania. Testowanie zmiennej może uniknąć testowania złożonych warunków i może również zbierać wyniki z kilku testów w pętlach wewnętrznych.

x_loop_must_break = False 
    for x in range(10): 
     for y in range(10): 
      print x*y 
      if x*y > 50: 
       x_loop_must_break = True 
       break 
     if x_loop_must_break: break 
28

Użyj itertools.product!

from itertools import product 
for x, y in product(range(10), range(10)): 
    #do whatever you want 
    break 

Oto link do itertools.product w dokumentacji Pythona: http://docs.python.org/library/itertools.html#itertools.product

+1

Muszę zrobić jedną linijkę: >>> wydrukuj "\ n" .join (mapa (str, takewhile (lambda i: i <= 50, (x * y dla x, y w produkcie (xrange (10), xrange (10)))))) –

+1

to nie rozwiązuje głównego problemu łamania zagnieżdżonych pętli w pełnej ogólności –

+1

Tylko jeśli szukasz sposobu na wyjście z jednej pętli na raz, ale nadal możesz wyrwać się z obu. W tym celu można użyć funkcji lub wyjątku. Uważam, że ta metoda jest bardziej elegancka, gdy nie trzeba wyskakować z jednej z pętli naraz. –

13

Jeśli masz zamiar podnieść wyjątek, można podnieść StopIteration exception. To przynajmniej sprawi, że intencja będzie oczywista.

+3

To jest dobry pomysł. Nie wymaga tworzenia nowej klasy wyjątku i jest bardzo łatwy do odczytania. –

Powiązane problemy