Мой опыт работы в C #, и я только недавно начал программировать на Python. Когда выдается исключение, я обычно хочу обернуть его в другое исключение, которое добавляет больше информации, в то же время показывая полную трассировку стека. Это довольно легко в C #, но как мне это сделать в Python?
Например. в C # я бы сделал что-то вроде этого:
try
{
ProcessFile(filePath);
}
catch (Exception ex)
{
throw new ApplicationException("Failed to process file " + filePath, ex);
}
В Python я могу сделать нечто подобное:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file ' + filePath, e)
... но это теряет след внутреннего исключения!
Изменить: я хотел бы видеть оба сообщения об исключениях и трассировки стека и коррелировать их. То есть я хочу видеть в выводе, что исключение X возникло здесь, а затем исключение Y там - так же, как и в C #. Возможно ли это в Python 2.6? Похоже, лучшее, что я могу сделать до сих пор (основываясь на ответе Гленна Мейнарда), это:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]
Это относится как к сообщениям, так и к обоим трассировкам, но не показывает, какое исключение произошло в трассировке.
Ответы:
Python 2
Это просто; передать в качестве третьего аргумента трассировку.
Всегда делайте это, когда ловите одно исключение и повторно вызываете другое.
источник
raise MyException(str(e)), ...
и т. д.raise E() from tb
и.with_traceback(...)
raise
- это значение, передаваемое исключению (в случае, если первый аргумент является классом исключения, а не экземпляром). Так что если вы хотите , чтобы исключения своп, а не делатьraise MyException(str(e)), None, sys.exc_info()[2]
, то лучше использовать это:raise MyException, e.args, sys.exc_info()[2]
.from future.utils import raise_
иraise_(ValueError, None, sys.exc_info()[2])
.Python 3
В Python 3 вы можете сделать следующее:
Это будет производить что-то вроде этого:
источник
raise ... from ...
это действительно правильный способ сделать это в Python 3. Это требует больше голосов.Nakedible
Я думаю, это потому, что, к сожалению, большинство людей до сих пор не используют Python 3.future
пакет для достижения этой цели: python-future.org/compatible_idioms.html#raising-exceptions Например,from future.utils import raise_
иraise_(ValueError, None, sys.exc_info()[2])
.Python 3 имеет
raise
...from
условие для исключения цепи. Ответ Гленна хорош для Python 2.7, но он использует только трассировку исходного исключения и выбрасывает сообщение об ошибке и другие детали. Вот несколько примеров в Python 2.7, которые добавляют контекстную информацию из текущей области в сообщение об ошибке исходного исключения, но оставляют другие детали нетронутыми.Известный тип исключения
Эта разновидность
raise
оператора принимает тип исключения в качестве первого выражения, аргументы конструктора класса исключения в кортеже в качестве второго выражения и трассировку в качестве третьего выражения. Если вы работаете раньше, чем Python 2.2, см. Предупреждения наsys.exc_info()
.Любой тип исключения
Вот еще один пример более общего назначения, если вы не знаете, какие исключения может понадобиться вашему коду. Недостатком является то, что он теряет тип исключения и просто вызывает RuntimeError. Вы должны импортировать
traceback
модуль.Изменить сообщение
Вот еще один вариант, если тип исключения позволит вам добавить к нему контекст. Вы можете изменить сообщение об исключении, а затем пересмотреть его.
Это генерирует следующую трассировку стека:
Вы можете видеть, что он показывает строку, где
check_output()
был вызван, но сообщение об исключении теперь включает в себя командную строку.источник
ex.strerror
приходит? Я не могу найти какой-либо соответствующий хит для этого в документации по Python. Не должно ли это бытьstr(ex)
?IOError
является производным отEnvironmentError
, @hheimbuerger, который обеспечиваетerrorno
иstrerror
атрибуты.Error
, например, ValueError, вRuntimeError
перехватException
? Если я воспроизведу ваш ответ для этого случая, трассировка стека будет потеряна.В Python 3.x :
или просто
который будет распространяться,
MyException
но печатать оба исключения, если это не будет обработано.В Python 2.x :
Вы можете предотвратить печать обоих исключений, убив
__context__
атрибут. Здесь я пишу менеджер контекста с помощью, чтобы поймать и изменить исключение на лету (см http://docs.python.org/3.1/library/stdtypes.html для expanation того , как они работают)источник
e.__traceback__
атрибута!Я не думаю, что вы можете сделать это в Python 2.x, но что-то похожее на эту функциональность является частью Python 3. Из PEP 3134 :
Сравнение с C #:
Также обратите внимание, что Java, Ruby и Perl 5 также не поддерживают этот тип вещей. Цитирую еще раз:
источник
Для максимальной совместимости между Python 2 и 3, вы можете использовать
raise_from
вsix
библиотеке. https://six.readthedocs.io/#six.raise_from . Вот ваш пример (слегка измененный для ясности):источник
Вы можете использовать мой класс CausedException для объединения исключений в Python 2.x (и даже в Python 3 это может быть полезно в случае, если вы хотите указать более одного перехваченного исключения в качестве причины для вновь возникшего исключения). Может быть, это может помочь вам.
источник
Может быть, вы могли бы получить соответствующую информацию и передать ее? Я думаю что-то вроде:
источник
Предполагая, что:
raise ... from
решение)Вы можете использовать простое решение из документации https://docs.python.org/3/tutorial/errors.html#raising-exceptions :
Выход:
Похоже, ключевой элемент - это упрощенное ключевое слово «поднимать», которое стоит отдельно. Это повторно вызовет исключение в блоке исключений.
источник