else и finally
Представьте, что вы замешиваете тесто для пирога. Если тесто получилось, вы ставите его в духовку. Если не получилось, выбрасываете его. А миску моете в любом случае, что бы ни вышло.
У try есть ветки ровно для этих трёх случаев:
- ветка
except— «не получилось»; - ветка
else— «получилось, продолжаем»; - ветка
finally— «моем миску в любом случае».
Ветки else и finally пишутся после всех except, на одном уровне с try:
def show_double(text):
try:
n = int(text)
except ValueError:
print("bad", end=" ")
else:
print(n * 2, end=" ")
finally:
print("checked")
show_double("5") # 10 checked
show_double("x") # bad checkedДавайте посмотрим, что происходит при каждом вызове.
Вызов show_double("5"):
int("5")проходит, иnстановится5.- Ветка
exceptпропускается, аelseпечатает10. - Ветка
finallyпечатаетcheckedв той же строке.
Вызов show_double("x"):
int("x")возбуждаетValueError, и блокtryпрерывается.- Ветка
exceptпечатаетbad, аelseпропускается. - Ветка
finallyснова печатаетchecked.
Ветка else
Ветка else выполняется, только если в блоке try не возникло исключения. Это слово уже встречалось у циклов, но здесь у него другой смысл: else у try значит «ошибки не было».
Тот же print(n * 2) можно было бы оставить внутри try. Но тогда except ValueError ловил бы ошибки и из этой строки, хотя защищать нужно только int(text). В else стоит код, ошибки которого этот try перехватывать не должен.
Запомните правило: в try кладут только ту строку, которая может упасть ожидаемым образом. Всё, что продолжает работу после её успеха, уходит в else.
Ветка finally
Ветка finally выполняется всегда. Когда именно:
- после успешного
try; - после сработавшего
except; - даже когда исключение никто не перехватил — тогда Python сначала выполняет
finally, а потом печатает трассировку.
Поэтому в finally пишут завершающие действия, которые нельзя пропустить. Здесь аналогия с миской заканчивается: на кухне вы можете забыть её помыть, а Python ветку finally не забудет никогда.
У try с веткой finally может не быть ни одного except. Если функция выходит через return из try, except или else, finally всё равно выполняется — до того, как значение вернётся вызывающему коду:
def half(text):
try:
return int(text) // 2
finally:
print("half of", text, end=": ")
print(half("9")) # half of 9: 4Разберём по шагам:
- Вызов
half("9")вычисляет4в строке сreturn. - Перед выходом из функции выполняется
finallyи печатаетhalf of 9:. - Только после этого внешний
printполучает4и печатает его в той же строке.
Вызов half("x") тоже напечатал бы half of x: , но затем программа остановилась бы с трассировкой: ValueError никто не перехватил.
На собеседовании любят спрашивать: «Выполнится ли finally, если в try стоит return?» Ответ — да, выполнится, и до того, как значение вернётся вызывающему коду.
Частая ошибка
В finally написали return:
def to_int(text):
try:
return int(text)
finally:
return 0 # ✗
print(to_int("7")) # 0
print(to_int("x")) # 0Python 3.12 не сообщает об ошибке. return в finally заменяет значение из try, поэтому to_int("7") возвращает 0. Он отменяет и исключение: ValueError из int("x") пропадает без трассировки. В finally оставляют только завершающие действия, а значение возвращают из try, except или else.
Главное
- Ветка
elseвыполняется, только если вtryне было исключения; в ней стоит код, ошибки которогоtryловить не должен. - Ветка
finallyвыполняется всегда: после успеха, послеexceptи перед трассировкой непойманного исключения. - При
returnизtryветкаfinallyвыполняется до того, как значение вернётся вызывающему коду. returnвfinallyзаменяет значение и отменяет исключение, поэтому там пишут только завершающие действия.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.