Для создания иерархии исключений в Python, нужно определить базовый класс исключения и затем наследовать от него дочерние классы для конкретных ситуаций.
class CustomError(Exception):
"""Базовый класс для пользовательских исключений."""
pass
class ValidationError(CustomError):
"""Ошибка валидации данных."""
pass
class NetworkError(CustomError):
"""Ошибка сети."""
pass
class ConnectionError(NetworkError):
"""Ошибка соединения."""
pass
try:
# Код, который может вызвать исключение
raise ConnectionError("Не удалось установить соединение.")
except ConnectionError as e:
print(f"Произошла ошибка соединения: {e}")
except NetworkError as e:
print(f"Произошла сетевая ошибка: {e}")
except CustomError as e:
print(f"Произошла пользовательская ошибка: {e}")
except Exception as e:
print(f"Произошла непредвиденная ошибка: {e}")
В примере выше: `CustomError` - базовый класс, `ValidationError` и `NetworkError` - его наследники. `ConnectionError` наследуется от `NetworkError`, создавая второй уровень иерархии. Обработчики исключений позволяют ловить исключения на разных уровнях иерархии.
Чтобы создать несколько уровней иерархии исключений в Python для различных ситуаций, необходимо создать пользовательские классы исключений, наследуя их от базового класса Exception
или от его подклассов (например, ValueError
, TypeError
, IOError
). Это позволяет организовать исключения логически и обрабатывать их более гранулярно.
Вот пример:
<!-- Пример кода Python -->
class ApplicationError(Exception):
"""Базовый класс для всех исключений приложения."""
pass
class ConfigurationError(ApplicationError):
"""Исключения, связанные с конфигурацией."""
pass
class MissingConfiguration(ConfigurationError):
"""Конфигурация отсутствует."""
def __init__(self, setting_name):
self.setting_name = setting_name
super().__init__(f"Не найдена конфигурация: {setting_name}")
class InvalidConfiguration(ConfigurationError):
"""Конфигурация недействительна."""
def __init__(self, setting_name, reason):
self.setting_name = setting_name
self.reason = reason
super().__init__(f"Недействительная конфигурация {setting_name}: {reason}")
class DataAccessError(ApplicationError):
"""Исключения, связанные с доступом к данным."""
pass
class DatabaseConnectionError(DataAccessError):
"""Ошибка подключения к базе данных."""
pass
class RecordNotFoundError(DataAccessError):
"""Запись не найдена."""
def __init__(self, record_id):
self.record_id = record_id
super().__init__(f"Запись с ID {record_id} не найдена")
# Пример использования
def load_config(setting_name):
# Имитация логики загрузки конфигурации
if setting_name == "database_url":
raise MissingConfiguration(setting_name)
elif setting_name == "api_key":
raise InvalidConfiguration(setting_name, "Key is too short")
else:
return "Some Value"
def get_data_from_db(record_id):
# Имитация логики доступа к базе данных
if record_id == 123:
raise DatabaseConnectionError("Failed to connect to database")
elif record_id == 456:
raise RecordNotFoundError(record_id)
else:
return {"id": record_id, "data": "Some data"}
try:
# load_config("database_url") # Вызовет MissingConfiguration
config_value = load_config("some_setting")
print(f"Config value: {config_value}")
except MissingConfiguration as e:
print(f"Ошибка конфигурации: {e}")
except InvalidConfiguration as e:
print(f"Ошибка конфигурации: {e}")
except ConfigurationError as e: # перехватывает все ConfigurationError
print(f"Общая ошибка конфигурации: {e}")
try:
get_data_from_db(456)
except DatabaseConnectionError as e:
print(f"Ошибка подключения к БД: {e}")
except RecordNotFoundError as e:
print(f"Запись не найдена: {e}")
except DataAccessError as e: # перехватывает все DataAccessError
print(f"Общая ошибка доступа к данным: {e}")
except ApplicationError as e: # Перехватит все ApplicationError
print(f"Общая ошибка приложения: {e}")
except Exception as e: # Ловит все не обработанные исключения.
print(f"Непредвиденная ошибка: {type(e).__name__}, {e}")
Основные моменты:
ApplicationError
, который наследуется от Exception
. Этот класс является корнем нашей иерархии.ConfigurationError
, DataAccessError
) для группировки связанных исключений.MissingConfiguration
, InvalidConfiguration
, DatabaseConnectionError
, RecordNotFoundError
), которые наследуются от соответствующих промежуточных классов.__init__
) для передачи дополнительной информации об ошибке, такой как имя отсутствующей настройки или ID записи.try...except
для перехвата исключений на разных уровнях иерархии. Важно располагать блоки except
от наиболее конкретных к наиболее общим, чтобы гарантировать, что конкретные исключения будут обработаны в первую очередь.except
имеет значение. Если первым идет except ApplicationError
, он перехватит *все* исключения, наследованные от него, и последующие блоки except
для более конкретных исключений никогда не будут выполнены.except Exception as e:
чтобы перехватить все необработанные исключения.Преимущества такой иерархии:
Например, можно перехватить все ConfigurationError
и предпринять общие действия (например, повторить попытку загрузки конфигурации), или перехватить конкретное MissingConfiguration
и вывести пользователю сообщение об отсутствии необходимой настройки.