Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Создание пользовательских исключений в Python
Пользовательские исключения позволяют создавать специфичные для вашего приложения ошибки, делая код более читаемым и позволяя обработчикам правильно реагировать на разные типы ошибок.
Базовые пользовательские исключения
# Простое исключение
class CustomError(Exception):
pass
# Использование
try:
raise CustomError("Что-то пошло не так")
except CustomError as e:
print(f"Ошибка: {e}")
Иерархия исключений
# Базовый класс для всех ошибок приложения
class ApplicationError(Exception):
pass
# Специфичные исключения
class ValidationError(ApplicationError):
pass
class DatabaseError(ApplicationError):
pass
class AuthenticationError(ApplicationError):
pass
class AuthorizationError(ApplicationError):
pass
# Использование
try:
if not email:
raise ValidationError("Email обязателен")
if not user_authenticated:
raise AuthenticationError("Пользователь не авторизован")
except ValidationError as e:
print(f"Ошибка валидации: {e}")
except AuthenticationError as e:
print(f"Ошибка аутентификации: {e}")
except ApplicationError as e:
print(f"Ошибка приложения: {e}")
Исключения с параметрами
class InvalidUserError(Exception):
def __init__(self, user_id, message="Пользователь не найден"):
self.user_id = user_id
self.message = message
super().__init__(self.message)
def __str__(self):
return f"Пользователь {self.user_id}: {self.message}"
# Использование
try:
raise InvalidUserError(user_id=123, message="ID не валиден")
except InvalidUserError as e:
print(f"Ошибка: {e}")
print(f"ID пользователя: {e.user_id}")
Исключения с кодами ошибок
class APIError(Exception):
def __init__(self, code, message, details=None):
self.code = code
self.message = message
self.details = details or {}
super().__init__(message)
def to_dict(self):
return {
"error_code": self.code,
"message": self.message,
"details": self.details
}
# Использование в FastAPI
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(APIError)
async def api_error_handler(request, exc):
return JSONResponse(
status_code=400,
content=exc.to_dict()
)
@app.get("/users/{user_id}")
async def get_user(user_id: int):
if user_id < 0:
raise APIError(
code="INVALID_ID",
message="ID пользователя не может быть отрицательным",
details={"provided_id": user_id}
)
Исключения с контекстом
class DatabaseConnectionError(Exception):
def __init__(self, host, port, original_error):
self.host = host
self.port = port
self.original_error = original_error
message = f"Не удалось подключиться к {host}:{port}"
super().__init__(message)
# Использование с цепочкой исключений
try:
try:
connection = connect_to_db(host, port)
except ConnectionRefusedError as e:
raise DatabaseConnectionError(host, port, e) from e
except DatabaseConnectionError as e:
print(f"Ошибка БД: {e}")
print(f"Оригинальная ошибка: {e.original_error}")
Практические примеры в приложении
# Для приложения с пользователями
class UserNotFoundError(ApplicationError):
def __init__(self, user_id):
self.user_id = user_id
super().__init__(f"Пользователь {user_id} не найден")
class DuplicateEmailError(ApplicationError):
def __init__(self, email):
self.email = email
super().__init__(f"Email {email} уже зарегистрирован")
class InsufficientPermissionsError(ApplicationError):
def __init__(self, user_id, required_role):
self.user_id = user_id
self.required_role = required_role
super().__init__(f"Пользователь {user_id} не имеет роль {required_role}")
# Использование в сервисе
class UserService:
def __init__(self, db):
self.db = db
def create_user(self, email, password):
if self.db.user_exists(email):
raise DuplicateEmailError(email)
return self.db.create(email, password)
def get_user(self, user_id):
user = self.db.get(user_id)
if not user:
raise UserNotFoundError(user_id)
return user
def delete_user(self, user_id, current_user_id):
if current_user_id != user_id:
raise InsufficientPermissionsError(current_user_id, "admin")
return self.db.delete(user_id)
Обработка исключений в Flask
from flask import Flask, jsonify
app = Flask(__name__)
class APIError(Exception):
def __init__(self, message, status_code=400):
self.message = message
self.status_code = status_code
@app.errorhandler(APIError)
def handle_api_error(error):
response = jsonify({"error": error.message})
response.status_code = error.status_code
return response
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
if user_id < 1:
raise APIError("ID должен быть положительным", status_code=400)
# ... остальной код
Логирование исключений
import logging
logger = logging.getLogger(__name__)
class ApplicationError(Exception):
def __init__(self, message, log_level=logging.ERROR):
super().__init__(message)
logger.log(log_level, f"Application error: {message}", exc_info=True)
class ValidationError(ApplicationError):
def __init__(self, message):
super().__init__(message, log_level=logging.WARNING)
# Использование
try:
validate_email(email)
except ValidationError as e:
# Логируется автоматически
pass
Контекстные менеджеры для исключений
from contextlib import contextmanager
@contextmanager
def handle_database_error():
try:
yield
except Exception as e:
logger.error(f"Database error: {e}")
raise DatabaseError(f"Ошибка БД: {str(e)}")
# Использование
with handle_database_error():
result = db.query("SELECT * FROM users")
Лучшие практики
- Наследуйте от Exception, не от BaseException
- Создавайте иерархию исключений для вашего приложения
- Используйте описательные имена (заканчивайте на "Error")
- Сохраняйте контекст в атрибутах исключения
- Не ловите все исключения (except Exception), ловите специфичные
- Логируйте полную трассировку стека
- Используйте raise from для цепочки исключений
- Документируйте какие исключения может выбросить функция
Чек-лист
- Иерархия исключений организована логично
- Каждый класс имеет ясное назначение
- Исключения содержат полезный контекст
- Обработчики ловят специфичные исключения
- Нет ловли всех исключений
- Логирование настроено правильно