7.1 Створення користувацьких виключень
Іноді стандартні виключення Python не повністю задовольняють потреби твого застосунку. В таких випадках ти можеш створювати свої власні виключення, успадкувавши їх від базового класу Exception або будь-якого іншого підходящого класу виключень.
Основи створення користувацьких виключень
Створення користувацького виключення включає в себе визначення нового класу, який наслідується від базового класу Exception. Ти можеш додати власні методи і атрибути в твій клас виключення для надання додаткової інформації про помилку.
Приклад створення простого користувацького виключення
Крок 1: Визначення користувацького виключення
class MyCustomError(Exception):
"""Клас для користувацького виключення."""
pass
Крок 2: Використання користувацького виключення
def check_value(value):
if value < 0:
raise MyCustomError("Значення не повинно бути менше нуля")
try:
check_value(-1)
except MyCustomError as e:
print(f"Сталося користувацьке виключення: {e}")
Все дуже просто. Головне, щоб твоє виключення було успадковане від класу Exception або одного з його нащадків.
7.2 Створення виключення з додатковими атрибутами
Ти можеш додавати атрибути і методи в твій клас виключення для передачі додаткової інформації про виниклу помилку.
Приклад:
class NegativeValueError( Exception ):
"""Клас для користувацького виключення при від'ємному значенні."""
def __init__(self, value, message = "Значення не повинно бути менше нуля"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Використання виключення з додатковими атрибутами
def check_value(value):
if value < 0:
raise NegativeValueError(value)
try:
check_value(-1)
except NegativeValueError as e:
print(f"Сталося користувацьке виключення: {e}")
Наше виключення — це клас, який успадкований від класу Exception. Тому з ним можна робити все те ж, що й з будь-яким іншим класом: додавати поля, методи, параметри конструктора і т.п.
Все для твого зручності, і зручності тих програмістів, які будуть перехоплювати твої виключення.
7.3 Створення ієрархії користувацьких виключень
Для більш складних застосунків корисно створювати ієрархії користувацьких виключень. Це дозволяє групувати пов'язані виключення і спрощує їх обробку.
Приклад:
class ApplicationError(Exception):
"""Базовий клас для всіх виключень застосунку."""
pass
class NegativeValueError(ApplicationError):
"""Клас для користувацького виключення при від'ємному значенні."""
def __init__(self, value, message="Значення не повинно бути менше нуля"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
class ValueTooLargeError(ApplicationError):
"""Клас для користувацького виключення при занадто великому значенні."""
def __init__(self, value, message="Значення занадто велике"):
self.value = value
self.message = message
super().__init__(self.message)
def __str__(self):
return f'{self.message}: {self.value}'
Використання ієрархії користувацьких виключень
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Сталося виключення: {e}")
except ValueTooLargeError as e:
print(f"Сталося виключення: {e}")
except ApplicationError as e:
print(f"Загальне виключення застосунку: {e}")
7.4 Порядок перехоплення виключень
При перехопленні виключень, особливо з однієї ієрархії, важливо вказувати їх правильний порядок. І хоча код всередині блоків except ніколи не виконується одночасно, вся справа в тому, що базовий клас виключення здатний захоплювати виключення всіх класів-нащадків.
Наприклад, код:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except ApplicationError as e: # захопить виключення типу ApplicationError і всіх його нащадків
print(f"Загальне виключення застосунку: {e}")
У блоці except будуть перехоплені виключення типу ApplicationError і всіх його класів-нащадків.
А оскільки всі виключення є нащадками класу Exception, то такий код захопить взагалі всі виключення:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except Exception as e:
print(f"Захоплення всіх виключень: {e}")
except ApplicationError as e: # Цей код ніколи не виконається
print(f"Загальне виключення застосунку: {e}")
Захоплення виключень у блоці except ApplicationError ніколи не станеться, тому що блок except Exception захопить взагалі всі виключення типу Exception і будь-яких його нащадків.
Рішення
Тому захоплювати виключення прийнято в порядку, зворотному успадкуванню: чим ближче клас до класу Exception, тим він нижче. Приклад:
def check_value(value):
if value < 0:
raise NegativeValueError(value)
elif value > 100:
raise ValueTooLargeError(value)
try:
check_value(150)
except NegativeValueError as e:
print(f"Сталося виключення: {e}")
except ApplicationError as e:
print(f"Загальне виключення застосунку: {e}")
except Exception as e:
print(f"Захоплення всіх виключень: {e}")
У цьому прикладі блоки except розташовані в порядку, що відповідає їх ієрархії успадкування: спочатку перехоплюються більш специфічні виключення, такі як NegativeValueError, потім більш загальні, такі як ApplicationError. Це дозволяє правильно обробляти виключення і уникати ситуацій, коли більш загальний обробник захоплює виключення до того, як його могли б обробити більш спеціалізовані блоки except.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ