Подтвердить что ты не робот

Оператор break в окончательном исключении блоков ласточек

Рассмотрим:

def raiseMe( text="Test error" ):
    raise Exception( text )

def break_in_finally_test():
    for i in range(5):
        if i==2:
            try:
                raiseMe()
            except:
                raise
            else:
                print "succeeded!"
            finally:
                print "testing this!"
                break

if __name__=='__main__':
    break_in_finally_test()

Я ожидал, что Exception( "Test error" ) будет поднят, но вместо этого будет напечатано только "тестирование этого". Разумеется, намерение состояло в том, чтобы вызвать raiseMe() только один раз, независимо от того, удастся нам это сделать или нет, но если это вызывает исключение, я бы хотел увидеть это!

Почему перерыв проглатывает исключение, которое я явно выражаю?

4b9b3361

Ответ 1

Из https://docs.python.org/2.7/reference/compound_stmts.html#finally:

Если, наконец, присутствует, он указывает "обработчик очистки". Предложение try выполняется, включая любые предложения except и else. Если исключение происходит в любом из предложений и не обрабатывается, исключение временно сохраняется.
Предложение finally выполняется. Если есть сохраненное исключение, оно будет повторно поднято в конце предложения finally. Если предложение finally добавляет другое исключение или выполняет оператор return или break, исключение сохраненного исключения отбрасывается

Это также отражает поведение, ожидаемое от оператора try...finally перед PEP341:

Вот как попытка, кроме последнего блока, выглядела как pre PEP341:

try:
    try:
        raiseMe()
    except:
        raise
finally:
    #here is where cleanup is supposed to happen before raising error
    break
    #after finally code: raise error

Так как повышение ошибок никогда не происходит в блоке finally, оно никогда не возникает.

Чтобы поддерживать обратную совместимость с версиями python 2.4 и менее, это должно было быть сделано таким образом.

Ответ 2

Из документа Документы по обработке ошибок:

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

Ваше исключение никогда не поднимается, потому что вы ломаетесь, прежде чем оператор try будет полностью оценен.

Ответ 3

Я полагаю, что это связано с тем, что перерыв фактически вызывает StopIteration, чтобы "вырваться" из цикла for. Это действительно не очень интуитивно понятно и не особенно хорошо документировано (не упомянуто в 1, например). Может быть, кто-нибудь подтвердит/объяснит это лучше?