Почему «продолжать» не разрешено в предложении «наконец» в Python?

StackOverflow https://stackoverflow.com/questions/8302293

Вопрос

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

>>> 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 пункт?

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

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

Если это важно, я использую Python 2.6.6.

Это было полезно?

Решение

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

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), тогда есть некоторое преимущество в том, чтобы оставить это как Ошибка синтаксиса.

Интересно, что вы можете положить возвращаться Внутри наконец-то оказалось, и это поглотит все исключения, включая Keyboardintrupt, SystemExit, а также MemoryError. Анкет Это, вероятно, тоже не очень хорошая идея ;-)

Другие советы

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

РЕДАКТИРОВАТЬ: Комментарий @mike Christensen к вопросу указывает на ветку, в которой неоднозначность этой конструкции обсуждается разработчиками Python Core. Кроме того, за более чем девять лет использования Python я никогда не хотел этого делать, так что, вероятно, это относительно необычная ситуация, когда разработчики не хотят тратить много времени.

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

Ошибка была Выпуск32489 - Разрешить «продолжить» в «наконец»..

Запрос на привлечение исправления: https://github.com/python/cpython/pull/5822

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

Поэтому ваш код ...

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 не допускает продолжение в конце блока, потому что весь код после продолжения никогда не будет выполнен. (Sparse лучше плотного.)

Я не видел его упомянутого в другом ответе, но я думаю, что вы могли бы хотеть в этом случае 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. В противном случае мы continue (а также i никогда не печатается)

Возможность поднять исключение, а затем просто проглотить, потому что вы используете 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, что угодно, и не просто заставляют это так же тупо. Как таковой, ИМХО continue внутри а finally должно быть разрешено, потому что я был бы признателен за написание чистого кода с использованием continue в finally Если это то, что мне нужно, вместо того, чтобы прибегать к обходному пути кода для этого ограничения (т.е. в философии Python «мы все согласны с взрослыми здесь»).

Теперь эта функция доступна с выпуском 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top