Исключения
Какие блоки для обработки исключений есть в Python?
подробнее
Существует 4 блока:
try- выполняется всегда, в него помещается код, который может отдать исключениеexcept- выполняется только в том случае если в блокеtryвозникло исключение, которое ловит этотexceptelse- выполняется в том случае еслиtryвыполнился без исключенийfinally- выполняется всегда в конце.
Можно ли использовать несколько except?
подробнее
Можно. Они будут обрабатываться в порядке очерёдности. (В Python блоки
exceptпроверяются сверху вниз до первого совпадения.)
«Узкие» (специфичные) исключения должны находиться выше, чем «широкие» (базовые). Пример: Если первым поставитьexcept Exception, то доexcept ValueErrorкод никогда не дойдет.
Все исключения унаследованы от BaseException:
BaseException
├── Exception
│ ├── ArithmeticError
│ │ ├── ZeroDivisionError
│ │ └── OverflowError
│ ├── ValueError
│ ├── IndexError
│ ├── KeyError
│ └── TypeError
├── SystemExit
└── KeyboardInterrupt
Раздельные блоки (разная логика для разных ошибок):
try:
raise ValueError(1)
except ValueError:
print('ValueError') # выполнится этот блок
except Exception:
print('Exception')
Группировка в кортеж (одна логика для нескольких ошибок):
try:
raise IOError(1)
except (ValueError, IOError) as e:
print('ValueError or IOError') # выполнится этот блок
except Exception:
print('Exception')
В чём разница между except и except Exception?
подробнее
exceptбезExceptionловитBaseException.
BaseException- это базовый класс для всех ошибок. ПерехватываяBaseExceptionбудет перехватываться вообще всё, включая системные прерывания (Ctrl+C).
Всегда рекомендуется использоватьexcept Exception.
Как вызвать исключение? Как рерайзнуть исключение?
подробнее
Как вызвать (возбудить) исключение
Используется синтаксис
raise ИмяИсключения("сообщение").
Пример:
if age < 0:
raise ValueError("Возраст не может быть отрицательным")
Как рерайзнуть (пробросить выше)
-
Чистый
raise(рекомендуемый)
Сохраняется весь исходный Traceback (стек вызовов), видно, где ошибка возникла изначально.try: 1 / 0 except ZeroDivisionError: print("Логируем ошибку...") raise # Пробрасывает ТУ ЖЕ САМУЮ ошибку дальше -
raise eexcept ZeroDivisionError as e: raise e # Traceback начнется с этой строки, оригинал потеряется -
Цепочка исключений (
from)
Показывает, что одна ошибка стала причиной другой (в консоли будет написано: The above exception was the direct cause…).except ZeroDivisionError as e: raise RuntimeError("Ошибка сервера") from e
Зачем нужны классы BaseExceptionGroup и ExceptionGroup?
подробнее
Эти классы появились в Python 3.11 для обработки ситуаций, когда одновременно возникает несколько независимых ошибок.
Раньше
raiseмог выбросить только одну ошибку. Но в современном коде (особенно в асинхронности или при работе с потоками) может упасть сразу несколько задач.
ExceptionGroupпозволяет упаковать список этих ошибок в один «контейнер» и пробросить его дальше.
Разница:
ExceptionGroup: Для обычных ошибок (наследуется отException). ВключаетValueError,TypeErrorи т.д.BaseExceptionGroup:Более «тяжелый» вариант (наследуется отBaseException). Включает системные ошибки вродеKeyboardInterrupt(Ctrl+C) илиSystemExit.
В чём разница между except и except*?
подробнее
except- для одиночных исключений. Нашел совпадение — остановился.
except*- для групп исключений. Проверяет все блоки и «выкусывает» из группы ошибки соответствующих типов, пока группа не опустеет.
Как это работает на практике:
except:
Если вылетит иValueError, иTypeError(хотя обычный код так не умеет),exceptпоймает только то, что прописано выше по коду. Остальное проигнорирует.except*:
Если вExceptionGroupлежат три ошибки (двеValueErrorи однаKeyError), то:
Блокexcept* ValueErrorзаберет обе ошибки этого типа.
Блокexcept* KeyErrorвыполнится следом и заберет свою.
Если в группе осталось что-то не пойманное, оно полетит дальше (re-raise) автоматически.
Пример:
try:
raise ExceptionGroup("Проблемы в сети", [
ValueError("Неверный формат"),
TypeError("Не тот тип")
])
except* ValueError as eg:
print(f"Обработали только ValueError: {eg.exceptions}")
except* TypeError:
print("Обработали только TypeError")
Как создать свой тип исключения?
подробнее
Создать свое исключение - значит создать класс, который наследуется от встроенного класса
Exception.
Примеры:
# Простое исключение
class MyError(Exception):
pass
raise MyError("Что-то пошло не так")
# Исключение с доп. логикой
class ValidationError(Exception):
def __init__(self, message, code):
super().__init__(message) # Передаем сообщение в базовый класс
self.code = code # Добавляем свое поле
raise ValidationError("Неверный пароль", 403)