Почему `continue` не разрешено в предложении` finally` в Python? - PullRequest
40 голосов
/ 29 ноября 2011

Следующий код вызывает синтаксическую ошибку:

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

Почему оператор continue не разрешен в предложении finally?

P.S. Этот другой код, с другой стороны, не имеет проблем:

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

Если это имеет значение, я использую Python 2.6.6.

Ответы [ 6 ]

26 голосов
/ 29 ноября 2011

Использование continue в пункте finally запрещено, поскольку его интерпретация была бы проблематичной. Что бы вы сделали, если бы предложение finally выполнялось из-за исключения?

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

Мы можем принять решение о том, что должен делать этот код, возможно, проглотив исключение; но хороший языковой дизайн говорит об обратном. Если код вводит читателей в заблуждение или если есть более ясный способ выразить предполагаемую логику (возможно, с помощью try: ... except Exception: pass; continue), то есть некоторое преимущество, если оставить это как SyntaxError .

Интересно, что вы можете поместить return в предложение finally, и оно поглотит все исключения, включая KeyboardInterrupt , SystemExit и MemoryError . Это, вероятно, тоже не очень хорошая идея; -)

6 голосов
/ 29 ноября 2011

Справочник по языку Python запрещает использование continue в предложении finally. Я не совсем уверен, почему. Возможно, потому что continue в предложении try обеспечивает выполнение finally, а решение о том, что continue должно делать в предложении finally, несколько неоднозначно.

Edit: @Mike Christensen в комментарии к вопросу указывает на нить, в которой неоднозначность этой конструкции обсуждается разработчиками ядра Python. Кроме того, за более чем девять лет использования Python я никогда не хотел этого делать, поэтому, вероятно, это относительно редкая ситуация, когда разработчики не хотят тратить много времени на это.

2 голосов
/ 01 декабря 2011

Возможность получить исключение, а затем просто проглотить, потому что вы используете continue, является сильным аргументом, но исключение также проглатывается, когда вы вместо этого используете break или return.

Например, это работает, и исключение проглатывается:

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

Это снова работает без ошибок (в функции), и исключение также проглатывается:

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

Так почему бы break и return быть разрешенными в блоке finally с возможными ошибками или без них, но continue нет?

Вы можете также рассмотреть комбинацию следующих факторов впроблема:

  • finally всегда выполняется;
  • continue «прерывает» текущую итерацию.

Это будет означать, что внутри каждогоцикл, потому что finally всегда выполняется, у вас всегда будет continue ведьма, которая в основном говорит "прервать текущую итерацию", "отменить текущую итерацию", "отменить текущую итерацию" ... ведьма не имеет никакого смысла,Но не имеет смысла использовать break и return.Текущая итерация также прерывается с той лишь разницей, что теперь у вас есть только одна итерация.

Так что вопрос "Почему continue не разрешен в finally?"также может быть задан вопрос «Почему разрешено break и return?».

Может быть, потому, что на тот момент имело смысл не делать этого? Это было решение разработчиков, и теперь оно такое, как есть? Конечно, это также может быть лень разработчика, но кто знает, может, они что-то имели в виду и, возможно, в другой версии Python это будет иметь больше смыслапо-другому?

Идея в том, что примеры здесь просто экстремальные .Вы не просто пишете такой код, не так ли?В блоке finally наверняка есть какая-то логика, чтобы сказать, когда нужно break/return/continue, что угодно, а не просто так тупо.Поэтому IMHO continue внутри finally должно быть разрешено, потому что я был бы признателен за написание чистого кода с использованием continue в finally, если это то, что мне нужно, вместо того, чтобы прибегать к обходному решению для этого ограничения (т.е.в философии Python «Мы все здесь взрослые по обоюдному согласию»).

2 голосов
/ 29 ноября 2011

Я не видел, чтобы это упоминалось в другом ответе, но я думаю, что вы, возможно, захотите в этом случае: 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

Блок else выполняется только в том случае, если исключений не было. Итак, что это значит:

  1. Мы print i
  2. Мы try до do_something_that_might_fail(i)
  3. Если он бросает SomeException, провалиться и print i снова
  4. В противном случае мы continuei никогда не печатается)
2 голосов
/ 29 ноября 2011

Я думаю, что причина этого на самом деле довольно проста. Оператор continue после ключевого слова finally выполняется каждый раз. Такова природа окончательного утверждения. Независимо от того, выдает ли ваш код исключение, не имеет значения. Наконец будет выполнено.

Поэтому твой код ...

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!

эквивалентно этому коду ...

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

, который чище и террее. Python не позволяет продолжить в блоке finally, потому что весь код после продолжения никогда не будет выполнен. (Разреженный лучше, чем плотный.)

1 голос
/ 20 апреля 2018

Оператор continue недопустим в предложении finally из-за проблемы с реализацией.В Python 3.8 это ограничение было снято.

Ошибка: issue32489 - Разрешить 'continue' в предложении 'finally' .

Запрос на получение исправления: https://github.com/serhiy-storchaka/cpython/pull/2

...