¿Cómo genero la misma excepción con un mensaje personalizado en Python?

Resuelto Kit asked hace 12 años • 16 respuestas

Tengo este trybloque en mi código:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise ValueError(errmsg)

Estrictamente hablando, en realidad estoy planteando otro ValueError , no el ValueErrorthrow by do_something...(), al que se hace referencia erren este caso. ¿ Cómo adjunto un mensaje personalizado err? Intento el siguiente código pero falla debido a que erruna ValueError instancia no es invocable:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)
Kit avatar Feb 06 '12 15:02 Kit
Aceptado

Si tienes la suerte de admitir solo Python 3.x, esto realmente se convierte en algo hermoso :)

subir de

Podemos encadenar las excepciones usando rise from .

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks') from e

En este caso, la excepción que captaría la persona que llama tiene el número de línea del lugar donde generamos nuestra excepción.

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

Observe que la excepción inferior solo tiene el seguimiento de la pila desde donde generamos nuestra excepción. La persona que llama aún podría obtener la excepción original accediendo al __cause__atributo de la excepción que detecta.

con_rastreo

O puedes usar with_traceback .

try:
    1 / 0
except ZeroDivisionError as e:
    raise Exception('Smelly socks').with_traceback(e.__traceback__)

Al utilizar este formulario, la excepción que detectaría la persona que llama tiene el rastreo desde donde ocurrió el error original.

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

Observe que la excepción inferior tiene la línea donde realizamos la división no válida, así como la línea donde volvemos a generar la excepción.

Ben avatar Apr 04 '2015 03:04 Ben

Actualización: para Python 3, consulte la respuesta de Ben

Actualización 2023 : escribí esta respuesta hace más de diez años y ahora hay mejores respuestas. Deberías usar Python 3 y la respuesta anterior.

Respuesta original:

Para adjuntar un mensaje a la excepción actual y volver a generarlo: (el intento/excepto externo es solo para mostrar el efecto)

Para Python 2.x donde 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)

Esto también hará lo correcto si errse deriva de ValueError. Por ejemplo UnicodeDecodeError.

Tenga en cuenta que puede agregar lo que quiera err. Por ejemplo err.problematic_array=[1,2,3].


Editar: @Ducan señala en un comentario que lo anterior no funciona con Python 3 ya que .messageno es miembro de ValueError. En su lugar, podrías usar esto (Python 2.6 o posterior válido o 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))

Editar2:

Dependiendo de cuál sea el propósito, también puede optar por agregar información adicional bajo su propio nombre de variable. Tanto para python2 como para 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
Johan Lundberg avatar Feb 06 '2012 08:02 Johan Lundberg

Esto sólo funciona con Python 3 . Puede modificar los argumentos originales de la excepción y agregar sus propios argumentos.

Una excepción recuerda los argumentos con los que se creó. Supongo que esto es para que puedas modificar la excepción.

En la función reraiseanteponemos los argumentos originales de la excepción con cualquier argumento nuevo que queramos (como un mensaje). Finalmente volvemos a generar la excepción preservando el historial de rastreo.

def reraise(e, *args):
  '''re-raise an exception with extra arguments
  :param e: The exception to reraise
  :param args: Extra args to add to the exception
  '''

  # e.args is a tuple of arguments that the exception with instantiated with.
  #
  e.args = args + e.args

  # Recreate the exception and preserve the traceback info so that we can see 
  # where this exception originated.
  #
  raise e.with_traceback(e.__traceback__)   


def bad():
  raise ValueError('bad')

def very():
  try:
    bad()
  except Exception as e:
    reraise(e, 'very')

def very_very():
  try:
    very()
  except Exception as e:
    reraise(e, 'very')

very_very()

producción

Traceback (most recent call last):
  File "main.py", line 35, in <module>
    very_very()
  File "main.py", line 30, in very_very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 28, in very_very
    very()
  File "main.py", line 24, in very
    reraise(e, 'very')
  File "main.py", line 15, in reraise
    raise e.with_traceback(e.__traceback__)
  File "main.py", line 22, in very
    bad()
  File "main.py", line 18, in bad
    raise ValueError('bad')
ValueError: ('very', 'very', 'bad')
shrewmouse avatar Jun 30 '2020 16:06 shrewmouse