Как работает обработка исключений в Python: блоки try, except, finally и else
Что проверяют
Знаете ли вы, зачем нужен else, и понимаете ли порядок выполнения finally.
Как отвечать
- try: код, который может выбросить исключение;
- except: обработка. Блоков может быть несколько, проверяются сверху вниз, срабатывает первый подходящий, поэтому конкретные типы идут раньше общих;
- else: выполняется, только если исключения не было. Нужен, чтобы в
tryоставался лишь тот код, который вы реально ожидаете сломаться; - finally: выполняется всегда, и при исключении, и при
return, и приbreak. Для освобождения ресурсов.
try:
conn = connect()
except ConnectionError as e:
log.warning("нет связи: %s", e)
raise
else:
process(conn) # только при успешном подключении
finally:
close_all() # в любом случаеЗачем else, если можно дописать в try: чем меньше кода в try, тем меньше шансов случайно перехватить исключение не оттуда, откуда ждали.
Тонкости, которые проверяют: finally с return перекрывает исключение и возвращаемое значение, поэтому так не пишут; raise без аргументов внутри except пробрасывает текущее исключение с исходной трассировкой; raise ... from e сохраняет причину; голый except: ловит и KeyboardInterrupt, поэтому пишут хотя бы except Exception.
Для ресурсов вместо try/finally обычно берут менеджер контекста (with), он делает то же самое короче.
Где спотыкаются
Пишут голый except и глушат прерывание с клавиатуры.
Ловят Exception там, где ожидается конкретный тип, и прячут настоящие ошибки.
Не знают про else и складывают всё в try.
Теряют исходное исключение, оборачивая его без from.