Странное поведение Try-Except-Else-finally с операторами Return

88

Это какой-то код, который ведет себя необычно. Это упрощенная версия поведения, которое я написал. Это все равно продемонстрирует странное поведение, и у меня возникли конкретные вопросы о том, почему это происходит.

Я использую Python 2.6.6 в Windows 7.

def demo1():
    try:
        raise RuntimeError,"To Force Issue"
    except:
        return 1
    else:
        return 2
    finally:
        return 3

def demo2():
    try:
        try:
            raise RuntimeError,"To Force Issue"
        except:
            return 1
        else:
            return 2
        finally:
            return 3
    except:
        print 4
    else:
        print 5
    finally:
        print 6

Полученные результаты:

>>> print demo1()
3
>>> print demo2()
6
3
  • Почему демо-версия возвращает 3 вместо 1?
  • Почему в демо-версии 2 печатается 6, а не 6 с 4 или 5?
Кайл Оуэнс
источник

Ответы:

124

Потому что finallyоператоры гарантированно будут выполнены (ну, при условии отсутствия отключения электроэнергии или чего-либо, находящегося вне контроля Python). Это означает, что перед тем, как функция сможет вернуться, она должна запустить блок finally, который возвращает другое значение.

В документах Python говорится :

Когда оператор return, break или continue выполняется в наборе try оператора try… finally, предложение finally также выполняется «на выходе».

Возвращаемое значение функции определяется последним выполненным оператором возврата. Поскольку предложение finally всегда выполняется, оператор return, выполняемый в предложении finally, всегда будет последним выполненным:

Это означает, что когда вы пытаетесь вернуться, finallyвызывается блок, возвращающий его значение, а не то, которое у вас было бы.

Гарет Латти
источник
4
почему во втором примере цифра 5 не выводится? я думаю, это все еще недостаточно хорошо объяснено. ответ на ответ хорошо дан, но почему 5 во втором примере не печатается
Joran Beasley
5
о, я думаю, я понял это, возвращение в первоначальной попытке заставляет его немедленно перейти к внешнему, наконец,
Джоран Бизли
2
Именно потому, что finallyблоки всегда запускаются.
Gareth Latty,
2
Во второй демонстрации, почему он выполняет вложенное, наконец, выводит наружу, наконец, затем возвращается во вложенное, наконец, чтобы завершить возврат, а не просто окончательно вернуть None извне?
Кайл Оуэнс
1
Поскольку при returnвызове оператора Python проверяет наличие любых открытых finallyпредложений, которые необходимо выполнить (см. Цитату выше).
Gareth Latty,
6

Порядок исполнения:

  1. попробуйте заблокировать все нормально завершается -> наконец блок -> функция завершается
  2. попробуйте запустить блок и попасть в исключение A -> наконец блок -> функция заканчивается
  3. try block сделать возвращаемое значение и вызвать return -> finally block -> всплывающее возвращаемое значение -> функция завершается

Таким образом, любой возврат в блоке finally завершит шаги заранее.

Фред Хуанг
источник