Генерация исключений: raise

Генерация исключений: raise

Мы умеем перехватывать исключения. Теперь научимся их генерировать самостоятельно. raise позволяет сигнализировать об ошибках из собственного кода — сообщать вызывающему, что переданные данные некорректны или операция невозможна.

Зачем генерировать исключения

Представьте функцию set_age(age). Возраст не может быть отрицательным. Как сообщить об ошибке? Можно вернуть None, можно напечатать сообщение — но это заставит вызывающий код везде проверять возврат. Стандартный Python-способ — выбросить исключение:

def set_age(age):
    if age < 0:
        raise ValueError(f"Возраст не может быть отрицательным: {age}")
    if age > 150:
        raise ValueError(f"Неправдоподобный возраст: {age}")
    return age

try:
    set_age(-5)
except ValueError as e:
    print(e)   # Возраст не может быть отрицательным: -5

Синтаксис raise

raise ExceptionType("описание ошибки")
raise ExceptionType   # без сообщения — допустимо, но менее информативно
raise               # без аргументов — перебросить текущее исключение (в except)

Создаётся экземпляр исключения и «бросается» вверх по стеку вызовов, пока кто-то его не перехватит. Если никто не перехватит — программа завершится с трейсбеком.

Выбор типа исключения

Используйте подходящий встроенный тип — это помогает вызывающему коду понять, что пошло не так:

def connect(host, port):
    if not isinstance(host, str):
        raise TypeError(f"host должен быть строкой, получен {type(host).__name__}")
    if not 1 <= port <= 65535:
        raise ValueError(f"Порт должен быть от 1 до 65535, получен {port}")
    # ... логика подключения

def load_user(user_id, users_db):
    if user_id not in users_db:
        raise KeyError(f"Пользователь {user_id} не найден")
    return users_db[user_id]

Перебросить исключение: raise без аргументов

Иногда нужно поймать исключение, выполнить какое-то действие (логирование) и снова бросить его дальше:

def process(data):
    try:
        result = complex_operation(data)
    except ValueError as e:
        print(f"Логирование ошибки: {e}")
        raise   # перебросить то же исключение дальше
    return result

Голый raise без аргументов повторно бросает текущее исключение, сохраняя его тип и трейсбек.

raise from: цепочка исключений

Когда одно исключение возникает вследствие другого, полезно сохранить контекст. raise X from Y явно указывает причинно-следственную связь:

def load_config(path):
    try:
        with open(path) as f:
            import json
            return json.load(f)
    except json.JSONDecodeError as e:
        raise ValueError(f"Невалидный конфиг в {path}") from e

При выводе Python покажет обе ошибки: оригинальную (JSONDecodeError) и новую (ValueError).

Практический пример: валидация данных

def create_user(name, age, email):
    if not isinstance(name, str) or not name.strip():
        raise ValueError("Имя не может быть пустым")
    if not isinstance(age, int) or not 0 <= age <= 120:
        raise ValueError(f"Некорректный возраст: {age}")
    if "@" not in email:
        raise ValueError(f"Некорректный email: {email}")
    return {"name": name.strip(), "age": age, "email": email}

try:
    user = create_user("Алиса", 25, "alice@example.com")
    print(user)
except ValueError as e:
    print(f"Ошибка создания пользователя: {e}")

Проверь себя

Что произойдёт, если вызвать raise вне блока except?

Python выбросит RuntimeError: No active exception to re-raise. Голый raise работает только внутри блока обработки исключений, чтобы перебросить активное исключение.

Итог

  • raise ExceptionType("message") — сгенерировать исключение с описанием.
  • Используйте встроенные типы: ValueError (плохое значение), TypeError (плохой тип), KeyError (ключ не найден).
  • raise без аргументов в except — перебросить текущее исключение.
  • raise X from Y — указать причину (исходное исключение).
  • Исключения — стандартный Python-способ сигнализировать о некорректных данных.

В следующем уроке узнаем, как создавать собственные классы исключений для точной типизации ошибок в ваших библиотеках и приложениях.

Попробуйте интерактивную версию

Практические задачи, квизы и AI-наставник — бесплатный старт без карты

Перейти к практике