Подтвердить что ты не робот

Использование Python "рейз из"

Какая разница между raise и raise from в Python?

try:
    raise ValueError
except Exception as e:
    raise IndexError

что дает

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError
IndexError

и

try:
    raise ValueError
except Exception as e:
    raise IndexError from e

что дает

Traceback (most recent call last):
  File "tmp.py", line 2, in <module>
    raise ValueError
ValueError

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

Traceback (most recent call last):
  File "tmp.py", line 4, in <module>
    raise IndexError from e
IndexError
4b9b3361

Ответ 1

Разница в том, что при использовании from __cause__ атрибут __cause__ и в сообщении указывается, что исключение было вызвано напрямую. Если вы опускаете from тогда никакая __cause__ не установлена, но атрибут __context__ может быть установлен, и в результате трассировки отображается контекст, как во время обработки чего-то еще, что произошло.

Установка __context__ происходит, если вы использовали raise в обработчике исключений; если вы использовали raise любом другом месте, то __context__ не устанавливается.

Если установлена __cause__, для __suppress_context__ = True также устанавливается флаг __suppress_context__ = True; если для __suppress_context__ задано значение True, __context__ игнорируется при печати трассировки.

При возврате из обработчика исключений, когда вы не хотите показывать контекст (не хотите, чтобы во время обработки другого сообщения об исключительной ситуации), используйте raise... from None чтобы установить для __suppress_context__ значение True.

Другими словами, Python устанавливает контекст для исключений, чтобы вы могли проанализировать, где возникло исключение, позволяя увидеть, было ли заменено другое исключение. Вы также можете добавить причину в исключение, сделав трассировку явной для другого исключения (используйте другую формулировку), и контекст игнорируется (но все же может быть подвергнут внутреннему анализу при отладке). Использование raise... from None позволяет вам подавить контекст печати.

См raise выражение documenation:

Предложение from используется для цепочки исключений: если дано, второе выражение должно быть другим классом или экземпляром исключения, который затем будет присоединен к __cause__ исключению как атрибут __cause__ (который доступен для записи). Если возникшее исключение не обработано, будут напечатаны оба исключения:

>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

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

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Подобный механизм работает неявно, если исключение вызывается внутри обработчика исключений или предложения finally: предыдущее исключение затем присоединяется как атрибут __context__ новых исключений:

>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Также см. Документацию " Встроенные исключения" для получения подробной информации о контексте и сведениях о причинах, прикрепленных к исключениям.