Можно ли наследовать собственное исключение от других встроенных классов, кроме `Exception`? Приведите пример.

Да, можно. Собственное исключение можно наследовать от любого встроенного класса исключений, который, в свою очередь, наследуется от `BaseException`. Например, можно наследовать от `ValueError` или `TypeError`, если это логически подходит для конкретной ситуации.
Пример:
  
  class InvalidAgeError(ValueError):
      def __init__(self, age, message="Возраст должен быть положительным и меньше 150"):
          super().__init__(message)
          self.age = age

  def set_age(age):
      if not 0 < age < 150:
          raise InvalidAgeError(age)
      print("Возраст установлен")

  try:
      set_age(-5)
  except InvalidAgeError as e:
      print(f"Ошибка: {e}, введенный возраст: {e.age}")

  
  

Да, можно наследовать собственные исключения от других встроенных классов исключений, кроме Exception. Основная идея в том, что все встроенные исключения, отличные от Exception, сами наследуются от Exception напрямую или через другие встроенные исключения. Поэтому любое исключение, которое вы создадите, в конечном итоге будет наследоваться от Exception, но при этом можно изменить его поведение или семантику, наследуясь от более специфического встроенного исключения.

Наследование от более конкретного встроенного исключения позволяет более точно классифицировать вашу ошибку и, возможно, упростить обработку исключений в других частях кода. Например, если ваше исключение связано с неверным типом данных, имеет смысл наследоваться от TypeError.

Вот пример:


class NegativeValueError(ValueError):
    """
    Исключение, возникающее, когда передано отрицательное значение,
    а ожидается положительное.  Наследуется от ValueError,
    потому что это связано с некорректным значением.
    """
    def __init__(self, value, message="Значение не может быть отрицательным"):
        self.value = value
        self.message = message
        super().__init__(self.message)  # Вызываем конструктор родительского класса

def process_positive_value(value):
    if value < 0:
        raise NegativeValueError(value)
    return value * 2


try:
    result = process_positive_value(-5)
    print(f"Результат: {result}")
except NegativeValueError as e:
    print(f"Ошибка: {e.message}, значение: {e.value}")
except ValueError as e:
    print(f"Другая ошибка ValueError: {e}") # Обработчик для других ошибок ValueError, если они возможны.

  

В этом примере NegativeValueError наследуется от ValueError. При перехвате исключений можно перехватывать либо конкретно NegativeValueError, либо более общее ValueError, что даёт большую гибкость.

Другие примеры: вы можете наследовать исключения от IndexError для проблем с индексацией, от IOError для проблем с вводом-выводом, от KeyError если отсутствует ключ в словаре (но обычно лучше просто перехватывать стандартный KeyError) и т.д.

Важно помнить, что не стоит создавать исключения без веской причины, и использовать их только в исключительных ситуациях (логично!). Лучше избегать использования исключений для простого контроля потока выполнения программы. Также стоит помнить о принципах DRY (Don't Repeat Yourself) и KISS (Keep It Simple, Stupid).

0