Как использовать несколько собственных исключений для разных типов ошибок в одном блоке `except`?

Можно использовать кортеж исключений в блоке except. Python обработает блок, если возникнет любое из исключений, перечисленных в кортеже. Например:

try:
    # Код, который может вызвать MyException1 или MyException2
    pass
except (MyException1, MyException2) as e:
    # Обработка MyException1 ИЛИ MyException2
    print(f"Ошибка: {e}")
except MyException3 as e:
    #Обработка MyException3
    pass
  
Также, можно использовать иерархию исключений, если они наследуются от общего базового класса. В этом случае, можно указать базовый класс в except и он будет ловить все дочерние исключения.

Для обработки нескольких собственных исключений разных типов в одном блоке except, можно использовать синтаксис группировки исключений. Python позволяет перечислить несколько исключений в кортеже, который будет передан в except.

Вот пример:


class ValidationError(Exception):
    pass

class NetworkError(Exception):
    pass

class DatabaseError(Exception):
    pass

def process_data(data):
    try:
        if not isinstance(data, dict):
            raise ValidationError("Data must be a dictionary.")

        if len(data) == 0:
            raise ValueError("Data dictionary cannot be empty.") # встроенное исключение

        # Допустим, здесь логика для отправки данных по сети
        raise NetworkError("Failed to connect to the server.") # для примера

        # Допустим, здесь логика для записи данных в базу данных
        raise DatabaseError("Failed to write to database.") # для примера

    except (ValidationError, NetworkError, DatabaseError) as e:
        print(f"Произошла ошибка: {type(e).__name__} - {e}")
        # Обработка ошибки для ValidationError, NetworkError и DatabaseError
        # Например, логирование ошибки, повторная попытка действия, отображение сообщения пользователю, и т.д.

    except ValueError as e:
        print(f"Произошла ошибка ValueError: {e}")
        #Обработка ValueError, если это необходимо.  В противном случае можно было бы не указывать этот except блок.
    except Exception as e:
        print(f"Произошла необработанная ошибка: {type(e).__name__} - {e}")
        # Обработка любых других исключений, которые не были пойманы ранее.
        # Очень важно иметь этот блок, чтобы предотвратить неожиданное завершение программы.

data = "invalid"
process_data(data)

data = {}
process_data(data)

data = {"key":"value"}
process_data(data) #выбросит NetworkError, а потом DatabaseError, но только первый будет обработан.
  

В этом примере, ValidationError, NetworkError и DatabaseError обрабатываются в одном блоке except. Если возникает любое из этих исключений, код в этом блоке except будет выполнен. Внутри блока except вы можете использовать e для доступа к объекту исключения и получения информации о нем (например, сообщения об ошибке).

Важно отметить, что порядок блоков except имеет значение. Если вы добавите Exception в начало списка исключений, то оно перехватит все исключения, включая и собственные, и код для собственных исключений никогда не будет выполнен. Старайтесь располагать более специфические исключения перед более общими.

Альтернативный способ (начиная с Python 3.11) - использовать except* для обработки групп исключений, когда может возникнуть несколько исключений одновременно. Это более продвинутый подход, подходящий для асинхронного программирования или случаев, когда несколько операций могут завершиться с ошибкой одновременно. Однако, стандартный подход с кортежем в except подходит для большинства ситуаций.

0