Как мне вызвать то же исключение с пользовательским сообщением в Python? - PullRequest
109 голосов
/ 06 февраля 2012

В моем коде есть блок 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)

Ответы [ 10 ]

118 голосов
/ 04 апреля 2015

Я понимаю, что этот вопрос уже давно существует, но как только вам посчастливится поддерживать только 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

Обратите внимание, что нижнее исключение имеет только трассировку стека, откуда мы подняли наше исключение.Ваш вызывающий абонент все еще может получить исходное исключение, обратившись к атрибуту __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

Обратите внимание, что нижнее исключение содержит строку, в которой мы выполнили недопустимое деление, а такжелиния, где мы переоцениваем исключение.

75 голосов
/ 06 февраля 2012

Обновление: Для Python 3, проверьте Ответ Бена


Чтобы прикрепить сообщение к текущему исключению и повторно вызвать его: (внешнийпопробуйте / исключить только для того, чтобы показать эффект)

Для 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 указывает в комментарии выше, что не работает с питоном 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
7 голосов
/ 06 февраля 2012
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'
6 голосов
/ 10 июня 2013

Кажется, что все ответы добавляют информацию в e.args [0], тем самым изменяя существующее сообщение об ошибке.Есть ли обратная сторона в расширении кортежа args?Я думаю, что возможный плюс в том, что вы можете оставить исходное сообщение об ошибке в одиночку для случаев, когда необходим анализ этой строки;и вы можете добавить несколько элементов в кортеж, если ваша пользовательская обработка ошибок вызвала несколько сообщений или кодов ошибок, для случаев, когда трассировка будет анализироваться программно (например, с помощью инструмента системного мониторинга).1004 *

## 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')

Можете ли вы увидеть недостатки этого подхода?

2 голосов
/ 04 августа 2016

Это функция, которую я использую для изменения сообщения об исключении в 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)
2 голосов
/ 12 июня 2012

Этот шаблон кода должен позволить вам вызвать исключение с помощью специального сообщения.

try:
     raise ValueError
except ValueError as err:
    raise type(err)("my message")
1 голос
/ 20 марта 2018

Либо создайте новое исключение с сообщением об ошибке, используя

raise Exception('your error message')

, либо

raise ValueError('your error message')

в месте, где вы хотите его поднять, ИЛИ прикрепите (замените) сообщение об ошибке в текущемисключение с использованием 'from':

except ValueError as e:
  raise ValueError('your message') from e
1 голос
/ 30 августа 2017

Встроенные исключения Python 3 имеют поле strerror:

except ValueError as err:
  err.strerror = "New error message"
  raise err
0 голосов
/ 01 июля 2015

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

Но выполнение приведенных ниже действий сохраняет трассировку и показывает добавленное сообщение независимо отисключение перехвачено или нет.

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)

0 голосов
/ 06 февраля 2012

Если вы хотите настроить тип ошибки, вы можете просто определить класс ошибки на основе ValueError.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...