Работа с исключениями в ООП: пользовательские типы ошибок

Зачем нужны пользовательские исключения? 🏗️

Когда стандартных исключений Python (ValueError, TypeError и др.) недостаточно, мы создаём свои! Это делает код:

  • Яснее — ошибки говорят на языке вашей предметной области
  • Контролируемее — вы решаете, какие данные передавать с ошибкой
  • Безопаснее — исключения можно группировать в иерархии

Пример из реального мира: банковское приложение. Ошибка InsufficientFundsError понятнее общего ValueError.


Создаём первое пользовательское исключение 🐣

Любое пользовательское исключение — это класс, унаследованный от Exception:

class MyCustomError(Exception):
    """Моё первое исключение!"""
    pass

Используем его:

def risky_operation():
    raise MyCustomError("Что-то пошло не так!")

try:
    risky_operation()
except MyCustomError as e:
    print(f"Поймали: {e}")

Добавляем логику в исключения ⚡

Исключения могут содержать методы и атрибуты, как обычные классы:

class TemperatureError(Exception):
    def __init__(self, temp, min_temp, max_temp):
        self.temp = temp
        self.min_temp = min_temp
        self.max_temp = max_temp
        message = f"{temp}°C не в диапазоне {min_temp}-{max_temp}°C"
        super().__init__(message)

def set_oven_temp(temp):
    if not 100 <= temp <= 250:
        raise TemperatureError(temp, 100, 250)
    print(f"Печь нагрета до {temp}°C")

try:
    set_oven_temp(300)
except TemperatureError as e:
    print(f"Ошибка печи: {e}. Переданная температура: {e.temp}°C")

Иерархия исключений в ООП 🌳

Создаём целое семейство ошибок для сложных систем:

class DatabaseError(Exception):
    """Базовое исключение для всех ошибок БД"""

class ConnectionError(DatabaseError):
    """Проблемы с подключением"""

class QueryError(DatabaseError):
    """Ошибки в SQL-запросе"""

def execute_query(query):
    if not query.startswith("SELECT"):
        raise QueryError(f"Неподдерживаемый запрос: {query}")
    print("Запрос выполнен!")

try:
    execute_query("DELETE * FROM users")
except DatabaseError as e:
    print(f"Ошибка базы данных: {type(e).__name__} - {e}")

Практика: система аутентификации 🔐

Создадим безопасную систему с понятными ошибками:

class AuthError(Exception):
    pass

class WeakPasswordError(AuthError):
    def __init__(self, password):
        self.password = password
        strength = self._check_strength()
        super().__init__(f"Пароль слишком {strength}")

    def _check_strength(self):
        if len(self.password) < 6:
            return "короткий"
        return "простой"

def register_user(username, password):
    if len(password) < 8:
        raise WeakPasswordError(password)
    print(f"Пользователь {username} зарегистрирован!")

try:
    register_user("admin", "123")
except WeakPasswordError as e:
    print(f"Ошибка регистрации: {e}")  # "Ошибка регистрации: Пароль слишком короткий"

Продвинутые техники 🚀

1. Модульные исключения — выносите ошибки в отдельный файл errors.py

2. Логирование — записывайте кастомные ошибки в лог:

import logging

logging.basicConfig(filename='app.log')

try:
    risky_call()
except CustomError as e:
    logging.error(f"Custom error occurred: {e}", exc_info=True)

3. Сериализация — передавайте исключения между процессами:

import pickle

error = pickle.dumps(MyError("Описание"))
restored_error = pickle.loads(error)

Главные правила пользовательских исключений 📜

  1. Ясность имёнPaymentFailedError лучше чем TransactionException
  2. Информативность — добавляйте полезные атрибуты для отладки
  3. Иерархия — стройте логические цепочки наследования
  4. Документируйте — пишите docstring для каждого класса ошибок

Как говорит Данила Бежин в своих видео: "Хорошие исключения — это не просто ошибки, это часть API вашей программы!" Смотрите его разборы на YouTube-канале.

Скрыть рекламу навсегда

🌱 Индвидидулаьные занятия

Индивидуальные онлайн-занятия по программированию для детей и подростков

Личный подход, без воды, с фокусом на понимание и реальные проекты.

🚀 Записаться на занятие