Короткий ответ
raise ... from original_error явно связывает новое исключение с исходным через атрибут __cause__, фиксируя в трассировке осознанную причину "одна ошибка вызвала другую"; без from при повторном raise внутри except исходное исключение всё равно попадает в трассировку через неявный __context__, но как побочный эффект обработки, а не как явно задокументированная причина.
Как это работает подробнее
Когда внутри except OriginalError: возбуждают новое исключение, Python автоматически сохраняет текущее исключение в атрибуте __context__ нового — это видно в трассировке как "During handling of the above exception, another exception occurred". raise New(...) from original дополнительно устанавливает __cause__ = original и меняет текст в трассировке на явное "The above exception was the direct cause of the following exception", что сигнализирует намеренную трансформацию ошибки, а не случайную.
Пример кода
class RepositoryError(Exception):
pass
def load_user(user_id):
try:
raise ConnectionError("Соединение с БД потеряно")
except ConnectionError as exc:
raise RepositoryError(f"Не удалось загрузить пользователя {user_id}") from exc
try:
load_user(42)
except RepositoryError as exc:
print("Поймано:", exc)
print("Причина:", exc.__cause__) # ConnectionError('Соединение с БД потеряно')Что использовать на практике
- Практика. Такой паттерн используют, когда низкоуровневая ошибка (например, ошибка драйвера БД) должна быть представлена вызывающему коду как ошибка более высокого уровня (например,
RepositoryError), но важно не терять оригинальную причину для логов и отладки.raise New(...) from Noneявно подавляет отображение цепочки, когда исходная ошибка не несёт полезной информации для внешнего наблюдателя.
Подводные камни
- Риски. Перехватывают исключение и поднимают новое без
from, теряя для читателя трассировки явную связь, хотя неявный__context__технически присутствует — это усложняет диагностику в логах, где печатают толькоstr(exc)без полного traceback. Также путаютraiseбез аргументов (повторно возбуждает текущее перехваченное исключение) сraise NewException() from current.