Блоки else и finally

Блоки else и finally в try/except Python: код при успехе, гарантированная очистка ресурсов и полная структура обработки ошибок.

Блок try/except можно расширить двумя необязательными секциями: else (выполняется, если ошибок не было) и finally (выполняется всегда — при успехе и при ошибке).

Полная структура

try:
    # рискованный код
    pass
except ТипОшибки:
    # если произошла ошибка
    pass
else:
    # если ошибок НЕ было
    pass
finally:
    # выполняется в любом случае
    pass

else — код при успехе

def parse_number(s):
    try:
        n = int(s)
    except ValueError:
        print(f'"{s}" — не число')
    else:
        # этот блок выполняется только если int(s) не выбросил ошибку
        print(f'Успешно: {n} * 2 = {n * 2}')

parse_number("10")
parse_number("привет")

Вывод:

Успешно: 10 * 2 = 20
"привет" — не число

Зачем нужен else, если можно просто написать код после try? Потому что код в else не перехватывается текущим except — если в нём возникнет ошибка, она не будет ошибочно поглощена.

finally — обязательная очистка

def read_config(path):
    f = None
    try:
        f = open(path, "r", encoding="utf-8")
        return f.read()
    except FileNotFoundError:
        print(f"Файл {path!r} не найден")
        return ""
    finally:
        if f:
            f.close()
            print("Файл закрыт")   # выполнится в любом случае

result = read_config("config.txt")
print("Результат:", repr(result))

Вывод:

Файл 'config.txt' не найден
Результат: ''

finally выполнится даже если функция вернёт значение через return или выбросит исключение. Это идеальное место для освобождения ресурсов: закрытия файлов, соединений с БД и т.д.

Все четыре блока вместе

values = [10, 20, 0, 5]

for v in values:
    try:
        result = 100 / v
    except ZeroDivisionError:
        print(f"{v}: ошибка деления")
    else:
        print(f"{v}: результат = {result:.1f}")
    finally:
        print(f"  (обработан элемент {v})")

Вывод:

10: результат = 10.0
  (обработан элемент 10)
20: результат = 5.0
  (обработан элемент 20)
0: ошибка деления
  (обработан элемент 0)
5: результат = 20.0
  (обработан элемент 5)

Коротко

  • else выполняется, только если в try не возникло исключений — удобен для кода, который зависит от успеха.
  • finally выполняется всегда — при успехе, ошибке, return и даже при необработанном исключении.
  • Используйте finally для освобождения ресурсов (файлы, соединения, блокировки).
  • На практике with заменяет большинство паттернов с finally для файлов.
Проверьте себя
1. Когда выполняется блок else в конструкции try/except/else?
AВсегда после try
BТолько если исключение было поймано
CТолько если в блоке try не возникло исключений
DТолько если блок finally завершился успешно
2. Когда выполняется блок finally?
AТолько при успехе
BТолько при ошибке
CВсегда — при успехе, ошибке, return и необработанном исключении
DТолько если нет блока except
3. Для чего в первую очередь используют блок finally?
AДля повторного выброса исключения
BДля логирования ошибок
CДля освобождения ресурсов (закрытие файлов, соединений)
DДля возврата значения функции
Поддержать проект