¿Cómo genero la misma excepción con un mensaje personalizado en Python?
Tengo este try
bloque 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 ValueError
throw by do_something...()
, al que se hace referencia err
en este caso. ¿ Cómo adjunto un mensaje personalizado err
? Intento el siguiente código pero falla debido a que err
una 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)
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.
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 err
se 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 .message
no 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
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 reraise
anteponemos 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')