Как я могу создать одно и то же исключение с помощью настраиваемого сообщения в Python?
У меня этот блок try
в моем коде:
try:
do_something_that_might_raise_an_exception()
except ValueError as err:
errmsg = 'My custom error message.'
raise ValueError(errmsg)
Строго говоря, я на самом деле поднимаю еще один ValueError
, а не ValueError
, который вызывается do_something...()
, который в этом случае называется err
. Как подключить настраиваемое сообщение к err
? Я пытаюсь выполнить следующий код, но сбой из-за err
, ValueError
экземпляра, не подлежащего вызову:
try:
do_something_that_might_raise_an_exception()
except ValueError as err:
errmsg = 'My custom error message.'
raise err(errmsg)
Ответы
Ответ 1
Обновление: Для Python 3, проверьте ответ Ben
Чтобы прикрепить сообщение к текущему исключению и повторно поднять его:
(внешний try/except - просто показать эффект)
Для python 2.x, где x >= 6:
try:
try:
raise ValueError # something bad...
except ValueError as err:
err.message=err.message+" hello"
raise # re-raise current exception
except ValueError as e:
print(" got error of type "+ str(type(e))+" with message " +e.message)
Это также сделает правильную вещь , если err
получен из ValueError
. Например UnicodeDecodeError
.
Обратите внимание, что вы можете добавить все, что хотите, к err
. Например err.problematic_array=[1,2,3]
.
Изменить: @Ducan указывает на комментарий, который выше не работает с python 3, поскольку .message
не является членом ValueError
. Вместо этого вы можете использовать это (действительный python 2.6 или более поздний или 3.x):
try:
try:
raise ValueError
except ValueError as err:
if not err.args:
err.args=('',)
err.args = err.args + ("hello",)
raise
except ValueError as e:
print(" error was "+ str(type(e))+str(e.args))
Edit2:
В зависимости от цели, вы также можете добавить дополнительную информацию под своим именем. Для python2 и python3:
try:
try:
raise ValueError
except ValueError as err:
err.extra_info = "hello"
raise
except ValueError as e:
print(" error was "+ str(type(e))+str(e))
if 'extra_info' in dir(e):
print e.extra_info
Ответ 2
Я понимаю, что этот вопрос существует некоторое время, но как только вам повезет поддерживать python 3.x, это действительно становится прекрасным:)
поднять из
Мы можем связать исключения с помощью рейза из.
try:
1 / 0
except ZeroDivisionError as e:
raise Exception('Smelly socks') from e
В этом случае исключение, которое ваш вызывающий абонент будет улавливать, имеет номер строки места, где мы вызываем наше исключение.
Traceback (most recent call last):
File "test.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "test.py", line 4, in <module>
raise Exception('Smelly socks') from e
Exception: Smelly socks
Обратите внимание, что в нижнем исключении есть только stacktrace, откуда мы подняли наше исключение. Ваш вызывающий абонент все еще может получить исходное исключение, обратившись к атрибуту __cause__
исключаемого ими исключения.
with_traceback
Или вы можете использовать with_traceback.
try:
1 / 0
except ZeroDivisionError as e:
raise Exception('Smelly socks').with_traceback(e.__traceback__)
Используя эту форму, исключение, которое ваш собеседник будет улавливать, имеет трассировку, откуда произошла исходная ошибка.
Traceback (most recent call last):
File "test.py", line 2, in <module>
1 / 0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 4, in <module>
raise Exception('Smelly socks').with_traceback(e.__traceback__)
File "test.py", line 2, in <module>
1 / 0
Exception: Smelly socks
Обратите внимание, что нижнее исключение имеет строку, в которой мы выполнили недействительное деление, а также строку, в которой мы делаем ререйз исключения.
Ответ 3
try:
try:
int('a')
except ValueError as e:
raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
print err
печатает:
There is a problem: invalid literal for int() with base 10: 'a'
Ответ 4
Кажется, что все ответы добавляют информацию в e.args [0], тем самым изменяя существующее сообщение об ошибке. Есть ли недостаток в расширении кортежа args? Я думаю, что возможный потенциал роста - вы можете оставить только исходное сообщение об ошибке для случаев, когда требуется разбор этой строки; и вы могли бы добавить несколько элементов в кортеж, если ваша пользовательская обработка ошибок выдала несколько сообщений или кодов ошибок, в случаях, когда трассировка будет анализироваться программно (например, с помощью средства мониторинга системы).
## Approach #1, if the exception may not be derived from Exception and well-behaved:
def to_int(x):
try:
return int(x)
except Exception as e:
e.args = (e.args if e.args else tuple()) + ('Custom message',)
raise
>>> to_int('12')
12
>>> to_int('12 monkeys')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')
или
## Approach #2, if the exception is always derived from Exception and well-behaved:
def to_int(x):
try:
return int(x)
except Exception as e:
e.args += ('Custom message',)
raise
>>> to_int('12')
12
>>> to_int('12 monkeys')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')
Вы видите недостаток этого подхода?
Ответ 5
Это функция, которую я использую для изменения сообщения об исключении в Python 2.7 и 3.x при сохранении исходной трассировки. Для этого требуется six
def reraise_modify(caught_exc, append_msg, prepend=False):
"""Append message to exception while preserving attributes.
Preserves exception class, and exception traceback.
Note:
This function needs to be called inside an except because
`sys.exc_info()` requires the exception context.
Args:
caught_exc(Exception): The caught exception object
append_msg(str): The message to append to the caught exception
prepend(bool): If True prepend the message to args instead of appending
Returns:
None
Side Effects:
Re-raises the exception with the preserved data / trace but
modified message
"""
ExceptClass = type(caught_exc)
# Keep old traceback
traceback = sys.exc_info()[2]
if not caught_exc.args:
# If no args, create our own tuple
arg_list = [append_msg]
else:
# Take the last arg
# If it is a string
# append your message.
# Otherwise append it to the
# arg list(Not as pretty)
arg_list = list(caught_exc.args[:-1])
last_arg = caught_exc.args[-1]
if isinstance(last_arg, str):
if prepend:
arg_list.append(append_msg + last_arg)
else:
arg_list.append(last_arg + append_msg)
else:
arg_list += [last_arg, append_msg]
caught_exc.args = tuple(arg_list)
six.reraise(ExceptClass,
caught_exc,
traceback)
Ответ 6
Текущий ответ не сработал у меня, если исключение не перехвачено, добавленное сообщение не отображается.
Но, как показано ниже, оба сохраняют трассировку и показывают добавленное сообщение независимо от того, перехвачено ли исключение или нет.
try:
raise ValueError("Original message")
except ValueError as err:
t, v, tb = sys.exc_info()
raise t, ValueError(err.message + " Appended Info"), tb
(я использовал Python 2.7, не пробовал его в Python 3)
Ответ 7
Встроенные исключения Python 3 имеют поле strerror
:
except ValueError as err:
err.strerror = "New error message"
raise err
Ответ 8
Этот шаблон кода должен позволять вам создавать исключение с помощью специального сообщения.
try:
raise ValueError
except ValueError as err:
raise type(err)("my message")
Ответ 9
если вы хотите настроить тип ошибки, вы можете просто определить класс ошибок на основе ValueError.