Короткий ответ
Сначала выполняется try; если исключения не было — выполняется else, затем всегда выполняется finally; если исключение возникло и было перехвачено — выполняется соответствующий except, затем finally; finally выполняется в любом случае, даже при исключении, return или необработанной ошибке.
Как это работает подробнее
Блок else в try/except — это код, который должен запуститься только тогда, когда try полностью завершился без исключений; он не выполнится, если исключение было поймано except'ом. finally гарантированно выполняется после try/except/else независимо от исхода: нормального завершения, перехваченного исключения или даже необработанного исключения, которое прокидывается дальше после finally.
Пример кода
example.py
def read_config(path):
try:
f = open(path)
except FileNotFoundError:
print("Файл не найден, используем значения по умолчанию")
return {}
else:
print("Файл успешно открыт") # выполнится только без исключения
data = f.read()
f.close()
return {"raw": data}
finally:
print("Попытка чтения конфигурации завершена") # выполнится всегда
read_config("missing.cfg")Что использовать на практике
- Практика.
elseиспользуют, чтобы не прятать код, зависящий от успеха операции, внутрь try — это снижает риск случайно перехватить исключение, брошенное уже в коде "после успеха".finallyприменяют для гарантированного освобождения ресурсов (закрытие файлов, соединений), хотя для этого чаще используют контекстные менеджеры (with).
Подводные камни
- Риски. Кладут в try слишком много кода, из-за чего except неожиданно перехватывает ошибки из логики, не связанной с рискованной операцией. Не замечают, что
returnвнутри try всё равно не отменяет выполнениеfinally— finally выполнится перед фактическим возвратом значения.