else и finally: два хвоста try
Два хвоста try: else работает при успехе, finally — при любом исходе. Разбираем порядок try, except, else, finally и место каждого блока.
Редакция Питоники
К конструкции try и except у Python есть два дополнения, которые делают её завершённой. else отвечает на вопрос «что делать при успехе», finally — «что делать при любом исходе». Оба блока часто пропускают в первых программах, и зря: без else успешный код живёт в try и рискует попадать под обработчик, а без finally некуда поставить финальную уборку. Разберём оба хвоста по очереди.
else: если не упало
Блок else выполняется ровно в одном случае — try прошёл целиком, без единого исключения. Тогда после try управление уходит в else:
try:
n = int('42')
except ValueError:
print('Не число')
else:
print('Разобрали:', n)
Разобрали: 42
Разбор прошёл — выполнение перешло в else, где переменная n уже существует и готова к работе. А теперь тот же каркас со значением, которое не разбирается:
try:
n = int('сорок два')
except ValueError:
print('Не число')
else:
print('Разобрали:', n)
Не число
ValueError уронил try — выполнение ушло в except, а else пропустили целиком. Получается чётное разделение: except работает при аварии, else при успехе, и оба не выполняются вместе. Финальные строки после конструкции выполняются при любом исходе — но код, который осмыслен только после успешного разбора, правильнее держать в else.
Зачем else, если есть try
Возникает вопрос: зачем отдельный блок, если код после разбора можно просто дописать в try? Причина — границы ответственности. Всё, что лежит в try, находится под охраной обработчика: любая его строка способна отправить выполнение в except. Допишем в try печать с опечаткой и посмотрим, что получится:
text = '18'
try:
n = int(text)
print('Разобрали:', n)
print('Длина текста:', len(texts))
except ValueError:
print('Не число')
Разобрали: 18
Traceback (most recent call last):
File "app.py", line 5, in <module>
print('Длина текста:', len(texts))
^^^^^
NameError: name 'texts' is not defined. Did you mean: 'text'?Разбор успел пройти, первая печать сработала — а опечатка в следующей строке упала мимо обработчика ValueError. Итог: половина блока выполнена, половина нет, и traceback указывает на строку, которая вообще не имела отношения к рискованной операции. Теперь тот же код с else — границы честные, try держит только разбор:
text = '18'
try:
n = int(text)
except ValueError:
print('Не число')
else:
print('Разобрали:', n)
print('Длина текста:', len(text))
Разобрали: 18 Длина текста: 2
Теперь try — только разбор, а весь код, который осмыслен при успехе, живёт в else. Ошибка в else не попадает под except того же try: блоки равноправны, и опечатка здесь упала бы громко, как и положено багу. Правило статьи: в try — рискованная операция, в except — реакция на её аварию, в else — то, что имеет смысл только после успеха.
finally: всегда
Второй хвост — finally. Его обещание звучит безусловно: этот блок выполнится при любом исходе. Успех — выполнится, авария с обработкой — выполнится. Проверим на списке попыток:
for text in ['7', 'кот']:
try:
n = int(text)
print('Разобрали:', n)
except ValueError:
print('Не число:', text)
finally:
print('--- попытка завершена')
Разобрали: 7 --- попытка завершена Не число: кот --- попытка завершена
Первый проход прошёл через try и finally, второй — через except и всё равно через finally. Ни один шаг цикла не закончился без строки «попытка завершена» — в этом и смысл блока: он держит код, который обязан случиться. Классические жильцы finally: закрыть файл, отпустить соединение, засечь время, уменьшить счётчик попыток. Уборка не должна зависеть от того, как закончилась работа.
attempts = ['12', 'x', '8']
good = 0
for text in attempts:
try:
n = int(text)
except ValueError:
print(text, ': не число')
else:
good += 1
print(text, ': число', n)
finally:
print(text, ': попытка окончена')
print('Успешных попыток:', good)
12 : число 12 12 : попытка окончена x : не число x : попытка окончена 8 : число 8 8 : попытка окончена Успешных попыток: 2
Полный каркас из четырёх частей на одной программе: try держит разбор, except — вердикт о сбое, else — учёт успеха, finally — строку о завершении каждой попытки. Смотрите, как аккуратно разделились обязанности: каждое сообщение программы отвечает ровно за один факт.
finally даже при падении
Самое сильное обещание finally — выполнение даже тогда, когда исключение никто не поймал. Уберём обработчик и оставим только finally:
print('до ошибки')
try:
n = 10 / 0
finally:
print('убираем за собой')
print('сюда не дойдём')
до ошибки
убираем за собой
Traceback (most recent call last):
File "app.py", line 3, in <module>
n = 10 / 0
~~~^~~
ZeroDivisionError: division by zeroРазберите вывод построчно: «до ошибки» — обычный код, «убираем за собой» — finally, и только затем traceback. Python не показал аварию, пока не выполнил обещание блока. Блок finally выполняется всегда: после except, после else и даже когда исключение никто не поймал. А строка «сюда не дойдём» так и осталась невыполненной — падение после finally всё-таки падение.
Порядок частей
Все четыре части собираются в жёстком порядке: try, затем один или несколько except, затем else, последним finally. Хвосты необязательны, но переставлять их нельзя — Python проверит структуру ещё до запуска:
try:
x = 1
else:
print(x)
Зато finally может обходиться без единого except — мы видели это в прошлом блоке: try и finally законны сами по себе. Комбинации такие: try + except (минимум), try + finally (без обработки), полный набор try + except + else + finally.
try:
n = int('5')
except ValueError:
print('except')
else:
print('else')
finally:
print('finally')
else finally
Успех пропустил except и прошёл через else и finally — ровно в том порядке, в котором блоки стоят. Схема выполнения получается линейной: try, потом ровно одна ветка (except или else), потом finally.
| Блок | Когда выполняется | Что в него кладут |
|---|---|---|
| try | Всегда, первым | Только рискованную операцию |
| except | При исключении своего типа | Реакцию на аварию |
| else | Когда try прошёл без исключений | Код, зависящий от успеха |
| finally | При любом исходе, даже без обработчика | Уборку: закрыть, отпустить, засечь |
Четыре части try собраны и разложены по местам. Остался последний инструмент, который превращает обработку из оборонительной в наступательную: собственные исключения. В уроке про raise мы будем бросать ошибки сами — когда данные нарушают правила программы. А если хочется освежить базовую пару, она разобрана в уроке про try и except.
Сначала предскажи ответ в голове — это главный навык программиста.
try:
n = int('9')
except ValueError:
print('А')
else:
print('Б')
finally:
print('В')
try:
n = int('девять')
except ValueError:
print('А')
else:
print('Б')
finally:
print('В')
for t in ['4', 'x']:
try:
n = int(t)
except ValueError:
print(t, 'сбой')
else:
print(t, 'успех')
finally:
print('---')
1. Когда выполняется блок else в конструкции try?
2. Что гарантирует блок finally?
3. Зачем выносить успешный код из try в else?
4. Какой порядок частей правильный?
5. Законна ли конструкция try с finally без единого except?
6. Исключение никто не поймал, но в конструкции есть finally. Что напечатается?
7. Ошибки из блока else попадут под except того же try?
8. Куда положить закрытие файла, которое нужно и при успехе, и при сбое?
Дан список attempts = ['12', 'кот']. Для каждой строки: при успехе печатай «12 : число 12», при сбое — «кот : не число», а после каждой попытки — «<текст> : попытка окончена». Используй try, except, else и finally.
Что делает else в конструкции try except python?
Блок else выполняется, только если try прошёл без исключений. Туда кладут код, зависящий от успеха: печать результата, подсчёт, продолжение работы. При аварии else пропускается — работает except.
Урок 7: raise — бросаем исключение самиКогда выполняется finally в python?
Всегда: при успехе после try, при аварии после except, и даже когда исключение никто не поймал — Python сначала выполнит finally, потом покажет traceback. Поэтому в finally ставят уборку: закрытие файла, освобождение ресурса.
Можно ли написать try и finally без except?
Да, это законная комбинация: try держит рискованный код, finally — безусловную уборку. А вот try с else без except не запускается: Python ответит SyntaxError: expected 'except' or 'finally' block.
Чем else отличается от кода после конструкции?
Строки после try/except выполняются при любом исходе. Else — только при успехе. Если код имеет смысл лишь после успешной операции (например, печатать n после разбора), его место в else — там он не выполнится с несуществующим n при аварии.
Почему успешный код не стоит держать в try?
Всё, что лежит в try, охраняется обработчиком: любая случайная ошибка там уходит в except или падает посреди блока. Границы читаются хуже, а вердикты врут. В try — только рискованная операция, в else — то, что осмысленно после успеха.
Понравился урок? Сошлитесь на него
«Блок finally выполняется всегда: после except, после else и даже когда исключение никто не поймал.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Исключения · Урок 2
try и except: ловим ошибку и не падаем
Первый запасной план: try держит рискованный код, except — что делать, если он упал. Прыжки, пропуски и try внутри цикла — на живом коде.
Исключения · Урок 5
as e: объект ошибки в переменной
Обработчик узнаёт больше, если взять ошибку в переменную: except ValueError as e даёт тип, сообщение и аргументы исключения.
Исключения · Урок 7
raise: бросаем исключение сами
До сих пор ошибки бросал Python. Теперь научимся бросать сами: raise ValueError с понятным текстом, когда данные нарушают правила программы.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
aiogram · Урок 9
Обработка ошибок в телеграм-боте: try/except, лимиты и логи
Учим бот переживать ошибки: try/except в хендлерах, лимиты Telegram с RetryAfter, модуль logging вместо print и перезапуск polling после падения.
обработка ошибок pythontry except python
Pandas · Урок 4
Очистка данных в Pandas: пропуски NaN, дубликаты и типы
Настоящая грязная выгрузка из CRM: пропуски NaN, дубликаты и цены-строки. Чистим её isna, dropna, fillna, drop_duplicates и astype — шаг за шагом.
обработка пропусков pandasобработка отсутствующих значений pandas
Исключения · Урок 3
except ValueError: ловим конкретный тип ошибки
Уточняем обработчик: except ValueError ловит только свой тип ошибок. Почему голый except прячет опечатки и как ValueError ведёт себя у int и list.remove.
except valueerror pythontry except python