2011-11-28 23 views
36

Poniższy kod zgłasza błąd składni:Dlaczego `continue` jest niedozwolone w klauzuli` finally` w Pythonie?

>>> for i in range(10): 
...  print i 
...  try: 
...  pass 
...  finally: 
...  continue 
...  print i 
... 
    File "<stdin>", line 6 
SyntaxError: 'continue' not supported inside 'finally' clause 

Dlaczego nie jest continue oświadczenie dozwolone wewnątrz finally klauzuli?

P.S. Ten inny kod z drugiej strony nie ma problemów:

>>> for i in range(10): 
...  print i 
...  try: 
...  pass 
...  finally: 
...  break 
... 
0 

Jeśli to ma znaczenie, używam Pythona 2.6.6.

+2

Wygląda jak czyste lenistwo? http://www.gossamer-threads.com/lists/python/dev/484210 –

+0

@Mike Christensen: Znalazłem również ten wątek, ale doktorzy mówią: "kontynuuj może wystąpić tylko syntaktycznie zagnieżdżone w pętli for lub while, ale nie zagnieżdżone w definicji funkcji lub klasy ** lub w klauzuli finally w tej pętli ** ". Czy to lenistwo, czy to było coś celowego, co później wymagało zmiany? ... jak wiele rzeczy w Pythonie ... – ElenaT

+0

Czy przeczytałeś cały wątek? - Istnieje kilka interesujących informacji na temat tego, co to znaczy "kontynuować" w bloku finally i różne problemy, które mogą pojawić się. Warto przeczytać. –

Odpowiedz

24

Użycie kontynuuje w klauzuli końcowej jest zabronione, ponieważ jego interpretacja byłaby problematyczna. Co zrobiłbyś, gdyby klauzula finally została wykonana z powodu wyjątku?

for i in range(10): 
    print i 
    try: 
     raise RuntimeError 
    finally: 
     continue  # if the loop continues, what would happen to the exception? 
    print i 

Możemy podjąć decyzję o tym, co powinien zrobić ten kodeks, może połknąć wyjątek; ale dobry projekt językowy sugeruje inaczej. Jeśli kod myli czytelników lub jeśli istnieje wyraźniejszy sposób wyrażenia zamierzonej logiki (być może z try: ... except Exception: pass; continue), istnieje pewna korzyść pozostawiając to jako SyntaxError.

Co ciekawe, można umieścić zwrot wewnątrz wreszcie-klauzuli i będzie przełknąć wszystkie wyjątki w tym KeyboardInterrupt, SystemExit i MemoryError. To chyba nie jest dobry pomysł ;-)

+4

Zgadzam się. Użycie klauzuli finally ogólnie wiąże luźne końce, jeśli wyjątek przerwał twoją procedurę. Aby "w końcu kontynuować" (również bezsensowne w języku angielskim) groziło powtórzenie wyjątku, dopóki pętla nie zakończy się, lub nawet nieskończenie ją powtórzy, jeśli wystąpi problem wpływający na sam stan pętli. – paislee

+2

A kontynuacja w bloku finally może być obsługiwana w taki sam sposób, jak powrót lub podbicie. W tym przykładzie wyjątek zostanie połknięty i pętla będzie kontynuowana. –

+2

Myślę, że ludzie zapominają, że kod w bloku 'finally' ZOSTAŁ ZAWSZE WYKONANY. – jathanism

6

Python Language Reference forbids the use of continue w klauzuli finally. Nie jestem do końca pewien, dlaczego. Być może dlatego, że klauzula continue w klauzuli try zapewnia wykonanie finally i podjęcie decyzji, co powinno zrobić continue w ramach klauzuli finally, jest nieco niejednoznaczne.

Edytuj: Komentarz @Mike Christensen do pytania wskazuje wątek, w którym niejednoznaczność tej konstrukcji jest dyskutowana przez głównych twórców Pythona. Dodatkowo, od ponad dziewięciu lat używania Pythona, nigdy nie chciałem tego robić, więc jest to prawdopodobnie stosunkowo rzadka sytuacja, że ​​deweloperzy nie mają ochoty spędzać zbyt wiele czasu.

+0

Wydaje mi się dobrym wyjaśnieniem. Kombinacja 'finally' i' continue' jest zdecydowanie czymś wartym refaktoryzacji. – jsalonen

+2

Tak, w niektórych przypadkach czasami lepiej nie pozwolić programistom na zrobienie czegoś - w przeciwnym razie musisz sprecyzować, rozwiązać i naprawić wszelkie dziwactwa, które wynikają z decyzji o zezwoleniu na takie rzeczy. –

3

Myślę, że przyczyna tego jest całkiem prosta. Instrukcja continue po słowie finally jest wykonywana za każdym razem. Taka jest natura ostatecznego oświadczenia. To, czy twój kod zgłasza wyjątek, jest nieistotne. W końcu zostanie wykonany.

Dlatego kod ...

for i in range(10): 
    print i 
    try: 
     pass 
    finally: 
     continue 
    print i # this (and anything else below the continue) won't ever be executed! 

jest równoznaczne z tym kodem ...

for i in range(10: 
    print i 
    try: 
     pass 
    finally: 
     pass 

który jest czystsze i terser. Python nie zezwala na kontynuowanie w bloku finally, ponieważ cały kod po kontynuacji nigdy nie zostanie wykonany. (Rzadki jest lepszy niż gęsty.)

2

nie widzę go wymienić w innych odpowiedzi, ale myślę, że to, co chcesz w tym przypadku jest try..else:

for i in range(10): 
    print i 
    try: 
     #pass <= I commented this out! 
     do_something_that_might_fail(i) 
    except SomeException: 
     pass 
    else: 
     continue 
    print i 

Blok else jest wykonywana tylko wtedy, gdy nie było wyjątkiem. Więc co to oznacza to:

  1. Mamy print i
  2. Mamy try do do_something_that_might_fail(i)
  3. Jeśli rzuca SomeException, wchodzą przez i print i ponownie
  4. W przeciwnym razie continue (i i nigdy nie jest drukowany)
2

Możliwość uzyskania wyjątku podniesiony, a następnie po prostu połknięcia, ponieważ yo używasz continue jest silnym argumentem, ale wyjątek jest również połknięty, gdy zamiast tego używasz break lub return.

Na przykład to działa i wyjątek połknięcia:

for i in range(10): 
    print i 
    try: 
     raise Exception 
    finally: 
     break 
    print i  # not gonna happen 

To znowu działa bez błędu (jeśli w funkcji) i wyjątek połknięcia zbyt:

for i in range(10): 
    print i 
    try: 
     raise Exception 
    finally: 
     return 
    print i  # not gonna happen 

Więc dlaczego będzie break i return być dozwolone w bloku finally, z lub bez możliwych błędów podnoszonych, ale continue nie?

Można również rozważyć kombinację następujących czynników w numerze:

  • finally jest zawsze wykonywany;
  • continue "Przerywa" bieżącą iterację.

będzie to oznaczać, że wewnątrz każdej pętli, z powodu finally zawsze wykonywać, będziesz zawsze mieć continue czarownicę zasadzie mówi „przerwanie bieżącej iteracji”, „przerwanie bieżącej iteracji”, „przerwanie bieżącej iteracji” .. Czarownica naprawdę nie ma żadnego sensu. Ale nie ma sensu również używać break i return. Bieżąca iteracja jest również przerywana z jedyną różnicą , która kończy się na jednej iteracji.

Pytanie "Dlaczego nie jest dozwolone continue w finally?" można również zadać pytanie "Dlaczego dozwolone są break i return?".

Może dlatego, że nie miało sensu w tym momencie? To była decyzja deweloperów, a teraz tak jest? Oczywiście, może to być również lenistwo realizatora, ale kto wie, może mieli coś na myśli i być może, w innej wersji Pythona, byłoby więcej sensu, aby mieć inny sposób?

Pomysł jest taki, że przykłady tutaj są po prostu ekstremalne. Nie piszesz po prostu takiego kodu, prawda? Z pewnością będzie pewna logika w bloku finally, aby powiedzieć, kiedy do break/return/continue, cokolwiek, a nie tylko tak to stępić. Jako takie, IMHO continue wewnątrz finally powinno być dozwolone, ponieważ byłbym wdzięczny napisanie czystego kodu przy użyciu continue w finally, jeśli tego właśnie potrzebuję, zamiast uciekania się do obejścia tego ograniczenia kodu (tj. W filozofii Pythona "Wszyscy jesteśmy zgoda dorosłych tutaj ").

+1

Trochę się spóźniłem na tę dyskusję, ale stwierdzenie "continue" wewnątrz klauzuli "finally" niekoniecznie oznacza, że ​​każda iteracja zostanie przerwana, ponieważ można zawrzeć instrukcję "continue" wewnątrz warunku. (Który wciąż jest wywołaniem Syntax.) – Fraxtil