Конструкция raise from в Python

В этом уроке вы узнаете, как использовать конструкцию raise from в Python для вызова исключения с дополнительным контекстом.

Содержание

Что такое оператор raise from в Python?

Оператор raise from имеет следующий синтаксис:

raise <ExceptionType> from <cause>

Технически это эквивалентно следующему:

ex = ExceptionType
ex.__cause__ = cause
raise ex

По умолчанию атрибут __cause__ объектов исключений всегда инициализируется значением None.

Пример с raise from

Следующая функция divide() делит число на другое и возвращает результат деления:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('b must not be zero')

Функция divide() имеет обработчик исключений, который перехватывает исключение ZeroDivisionError. Внутри обработчика мы вызываем новое исключение ValueError.

Если вы передадите ноль второму аргументу функции divide():

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('b must not be zero') from ex


divide(10, 0)

вы получите следующую трассировку стека:

Traceback(most recent call last):
  File "c:/python/app.py", line 3, in divide
    return a / b
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback(most recent call last):
  File "c:/python/app.py", line 8, in <module>
    divide(10, 0)
  File "c:/python/app.py", line 5, in divide
    raise ValueError('b must not be zero')
ValueError: b must not be zero

Сообщение импорта:

During handling of the above exception, another exception occurred:

Это означает, что пока вы обрабатывали исключение ZeroDivisionError, возникло исключение ValueError.

Чтобы указать Python, что вы хотите изменить и переслать исключение ZeroDivisionError, вы можете использовать оператор raise from следующим образом:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('b must not be zero') from ex

divide(10, 0)

Когда вы запустите код, вы получите следующую трассировку стека:

Traceback(most recent call last):
  File "c:/python/app.py", line 3, in divide
    return a / b
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback(most recent call last):
  File "c:/python/app.py", line 8, in <module>
    divide(10, 0)
  File "c:/python/app.py", line 5, in divide
    raise ValueError('b must not be zero') from ex
ValueError: b must not be zero

Теперь вы получаете исключение ValueError с причиной, добавленной к атрибуту __cause__ объекта исключения.

Следующий код изменяет приведенный выше код, чтобы отобразить атрибут __cause__ исключения ValueError:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as ex:
        raise ValueError('b must not be zero') from ex


try:
    divide(10, 0)
except ValueError as ex:
    print('cause:', ex.__cause__)
    print('exception:', ex)

Выход:

cause: division by zero
exception: b must not be zero

Python вызывает исключение из None

Если причина исключения не важна, вы можете опустить причину, используя оператор raise exception from None:

raise <ExceptionType> from None

Например, вы можете скрыть причину исключения ValueError в функции divide() следующим образом:

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        raise ValueError('b must not be zero') from None


try:
    divide(10, 0)
except ValueError as ex:
    print('cause:', ex.__cause__)
    print('exception:', ex)

Выход:

cause: None
exception: b must not be zero

Теперь __cause__ имеет значение None. Кроме того, функция divide() вызывает исключение ValueError без какой-либо дополнительной информации.

Если вы удалите оператор try из кода, вызывающего функцию divide():

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        raise ValueError('b must not be zero') from None


divide(10, 0)

вы получите следующую трассировку стека:

Traceback(most recent call last):
  File "c:/python/app.py", line 8, in <module>
    divide(10, 0)
  File "c:/python/app.py", line 5, in divide
    raise ValueError('b must not be zero') from None
ValueError: b must not be zero
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *