Конструкция 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