Почему `continue` не разрешено в` finally` в Python?
Следующий код вызывает синтаксическую ошибку:
>>> for i in range(10):
... print i
... try:
... pass
... finally:
... continue
... print i
...
File "<stdin>", line 6
SyntaxError: 'continue' not supported inside 'finally' clause
Почему в предложении finally
разрешен оператор continue
?
P.S. Этот другой код, с другой стороны, не имеет проблем:
>>> for i in range(10):
... print i
... try:
... pass
... finally:
... break
...
0
Если это имеет значение, я использую Python 2.6.6.
Ответы
Ответ 1
Использование продолжения в окончательной статье запрещено, поскольку ее интерпретация была бы проблематичной. Что бы вы сделали, если 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.
Интересно, что вы можете поместить возврат внутри finally-предложения, и он проглотит все исключения, включая KeyboardInterrupt, SystemExit и MemoryError. Это, вероятно, тоже не очень хорошая идея: -)
Ответ 2
Справочник по языку Python запрещает использование continue
в предложении finally
. Я не совсем понимаю, почему. Возможно, потому что continue
в предложении try
гарантирует выполнение finally
и решение о том, что continue
должно делать в предложении finally
, несколько неоднозначно.
Изменить: комментарий @Mike Christensen на вопрос указывает на поток, где эта неоднозначность конструкции обсуждается разработчиками ядра Python. Кроме того, в течение более чем девяти лет использования Python я никогда не хотел этого делать, поэтому, вероятно, это относительно необычная ситуация, когда разработчикам не хочется тратить много времени.
Ответ 3
Я думаю, что причина этого на самом деле довольно проста. Оператор 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, потому что весь код после продолжения никогда не будет выполнен. (Рельеф лучше плотного.)
Ответ 4
Я не видел, чтобы это упоминалось в другом ответе, но я думаю, что в этом случае вам может понадобиться 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
выполняется только в случае отсутствия исключения. Итак, что это значит:
- Мы
print i
- Мы
try
до do_something_that_might_fail(i)
- Если он выбрасывает
SomeException
, проваливается и print i
снова
- В противном случае мы
continue
(и i
никогда не печатаем)
Ответ 5
Возможность получить исключение, а затем просто усвоить, потому что вы используете 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
not?
Вы также можете рассмотреть комбинацию следующих факторов в проблеме:
-
finally
всегда выполняется;
-
continue
"прерывает" текущую итерацию.
Это будет означать, что внутри каждого цикла из-за того, что finally
всегда выполняется, у вас всегда будет continue
ведьма в принципе
говорит "прерывать текущую итерацию" , "прерывать текущую итерацию" , "прерывать текущую итерацию" ... ведьма на самом деле не имеет никакого смысла. Но не имеет смысла использовать break
и return
. Текущая итерация также прерывается с единственной разницей
что теперь у вас есть только одна итерация.
Итак, вопрос "Почему continue
не разрешено в finally
?"? также можно задать как "Почему break
и return
разрешено?".
Может быть, потому что это имело смысл не в тот момент? Это было решение разработчиков, и теперь это похоже на это. Конечно, это может быть и ленивость разработчика, но кто знает, может быть, они что-то имели в виду и, возможно, в другой версии Python, это сделало бы больше
смысл иметь это по-другому?
Идея состоит в том, что примеры здесь просто экстремальные. Вы не просто пишете такой код, не так ли? Конечно, есть некоторые
логики в блоке finally
, чтобы сказать, когда break/return/continue
, что угодно, и не просто так тупо. Таким образом, IMHO continue
внутри a finally
должно быть разрешено, потому что я хотел бы написать чистый код с использованием continue
в finally
, если это то, что мне нужно, вместо того, чтобы прибегать к обходному пути кода для этого ограничения (т.е. в философии Python "Мы все соглашаем взрослых здесь" ).
Ответ 6
Оператор continue недопустим в предложении finally из-за проблемы с реализацией. В Python 3.8 это ограничение было снято.
Ошибка была Issue32489 - разрешить "продолжить" в предложении "наконец".
Запрос на исправление для исправления: https://github.com/python/cpython/pull/5822
Ответ 7
Теперь эта функция доступна с версии 3.8
https://docs.python.org/3/whatsnew/3.8.html
Пример кода
def new_f():
for i in range(0,24):
try:
print(1/0)
except:
print('In Exception')
finally:
print('In finally')
continue