Exception
или его подклассов (например, ValueError
, TypeError
) для семантической связи.raise
): В случаях, когда стандартные исключения не отражают суть ошибки. Обязательно добавляйте информативные сообщения.try...except
): Используйте except
с вашим конкретным типом исключения для обработки специфичных ошибок. except Exception as e:
- старайтесь избегать (слишком общее).Exception
напрямую. Это усложняет отладку.Пример:
class InsufficientFundsError(Exception):
pass
def withdraw(amount, balance):
if amount > balance:
raise InsufficientFundsError("Недостаточно средств на счете")
return balance - amount
try:
new_balance = withdraw(100, 50)
except InsufficientFundsError as e:
print(f"Ошибка: {e}")
Правильное использование пользовательских исключений в Python позволяет сделать обработку ошибок более явной, читаемой и информативной. Вот основные принципы и примеры:
1. Создание собственных исключений:
Все пользовательские исключения должны наследоваться от базового класса Exception
или от одного из его подклассов (например, ValueError
, TypeError
, IOError
). Это позволяет использовать механизм try...except
для их перехвата.
class MyCustomError(Exception):
"""
Базовый класс для исключений в моем модуле.
"""
pass
class ValidationError(MyCustomError):
"""
Исключение, возникающее при ошибках валидации данных.
"""
def __init__(self, message, field=None):
super().__init__(message)
self.field = field # Дополнительная информация об ошибке
self.message = message
def __str__(self):
if self.field:
return f"ValidationError: {self.message} (field: {self.field})"
else:
return f"ValidationError: {self.message}"
class DatabaseConnectionError(MyCustomError):
"""
Исключение, возникающее при проблемах с подключением к базе данных.
"""
def __init__(self, message, connection_details=None):
super().__init__(message)
self.connection_details = connection_details
def __str__(self):
if self.connection_details:
return f"DatabaseConnectionError: {self.message} (details: {self.connection_details})"
else:
return f"DatabaseConnectionError: {self.message}"
2. Вызов исключений:
Используйте оператор raise
для выброса исключения, когда возникает ошибка.
def validate_data(data):
if not isinstance(data, dict):
raise ValidationError("Data must be a dictionary.")
if 'name' not in data:
raise ValidationError("Missing required field: 'name'", field='name')
if not isinstance(data['age'], int) or data['age'] < 0:
raise ValidationError("Invalid age value.", field='age')
# Пример вызова
try:
validate_data({"name": "Alice", "age": -5})
except ValidationError as e:
print(f"Error: {e}") # Выведет: Error: ValidationError: Invalid age value. (field: age)
try:
validate_data("not a dictionary")
except ValidationError as e:
print(f"Error: {e}") # Выведет: Error: ValidationError: Data must be a dictionary.
3. Обработка исключений:
Используйте блоки try...except
для перехвата и обработки исключений. Указывайте конкретные типы исключений, которые вы ожидаете. Это предотвращает случайный перехват непредвиденных ошибок.
def process_data(data):
try:
validate_data(data)
# Дальнейшая обработка данных
print("Data is valid, processing...")
except ValidationError as e:
print(f"Validation error: {e}")
# Обработка ошибки валидации (например, логирование, возврат ошибки пользователю)
except DatabaseConnectionError as e:
print(f"Database error: {e}")
except Exception as e: # Перехватывает все остальные исключения, не являющиеся ValidationError или DatabaseConnectionError
print(f"Unexpected error: {e}")
# Обработка других непредвиденных ошибок
# Важно: Старайтесь избегать перехвата общего Exception, если это возможно.
# Лучше перехватывать более конкретные типы исключений.
finally:
# Код, который будет выполнен в любом случае (например, закрытие файлов, освобождение ресурсов)
print("Processing complete.")
4. Преимущества использования пользовательских исключений:
5. Лучшие практики:
raise ... from ...
: При перехвате исключения и выбросе нового, используйте raise NewException from OriginalException
. Это сохраняет информацию о цепочке исключений, что полезно для отладки.Пример raise ... from ...
:
def connect_to_database(host, port):
try:
# Попытка установить соединение (здесь может быть какой-то код)
raise Exception("Failed to connect to the database") # Эмулируем ошибку
except Exception as original_exception:
raise DatabaseConnectionError(f"Could not connect to {host}:{port}") from original_exception
try:
connect_to_database("localhost", 5432)
except DatabaseConnectionError as e:
print(f"Database connection error: {e}")
if e.__cause__:
print(f"Original exception: {e.__cause__}") #выведет текст оригинальной ошибки
Использование пользовательских исключений – важный аспект разработки надежного и легко поддерживаемого Python кода. Оно позволяет сделать обработку ошибок более явной, информативной и гибкой.