Что такое цепочки исключений (raise from) и как правильно создавать свои исключения?
- Чем raise ... from ... отличается от raise внутри except?
- Как спроектировать иерархию исключений в Python-проекте?
raise NewError(...) from err сохраняет исходную ошибку в __cause__ — в трассировке «The above exception was the direct cause». Простой raise внутри except ставит __context__ («During handling … another exception occurred»). from None скрывает исходную. Свои исключения — иерархия от одного базового класса проекта.
- Ловить базовый класс библиотеки — удобно вызывающему
- Не ловить голый except: — перехватит KeyboardInterrupt и SystemExit
- add_note (3.11) — добавить контекст к исключению без обёртки
А ещё ExceptionGroup и except* (3.11) — несколько ошибок сразу
Подробно
Зачем цепочки. Оборачивая низкоуровневую ошибку в доменную, важно не потерять причину: в логе будут обе трассировки. Без from Python всё равно сохранит контекст, но сообщение будет выглядеть как ошибка в обработчике, а не намеренное преобразование.
Иерархия исключений:
- один базовый класс на библиотеку или модуль (
PaymentError); - подклассы по тому, как вызывающий будет реагировать (повторить, показать пользователю, упасть);
- данные в атрибутах, а не только в тексте:
CardDeclined(code=...).
Правила обработки: ловить узко, логировать один раз, не глотать молча, не использовать except Exception: pass. Голый except: перехватывает BaseException, включая KeyboardInterrupt, SystemExit и отмену asyncio.
ExceptionGroup (3.11) объединяет несколько независимых ошибок (TaskGroup, параллельная валидация); except* ValueError обрабатывает свою часть группы, остальные идут дальше.
Пример
class PaymentError(Exception): ...
class CardDeclined(PaymentError): ...
class ProviderUnavailable(PaymentError): ...
def charge(card):
try:
return gateway.charge(card)
except requests.Timeout as e:
raise ProviderUnavailable("шлюз не ответил") from eЧто хотят услышать
- __cause__ и __context__.
- Проектирование иерархии.
- Почему нельзя голый except.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗raise ... from err заменяет исходное исключение новым, а свои исключения лучше наследовать от BaseException
- ✗Голый except: — хорошая практика для надёжности
- ✗Свои исключения нельзя наследовать друг от друга
- ✓raise ... from err сохраняет причину в __cause__; свои исключения — иерархия от базового класса проекта
Разбор темы
- Исключения и контекстные менеджеры
try, except, else и finally, свои исключения и цепочки raise from, with и контекстные менеджеры, ExceptionGroup.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.