Mi experiencia es en C # y recientemente comencé a programar en Python. Cuando se produce una excepción, normalmente quiero incluirla en otra excepción que agregue más información y, al mismo tiempo, muestre el seguimiento completo de la pila. Es bastante fácil en C #, pero ¿cómo lo hago en Python?
P.ej. en C # haría algo como esto:
try
{
ProcessFile(filePath);
}
catch (Exception ex)
{
throw new ApplicationException("Failed to process file " + filePath, ex);
}
En Python puedo hacer algo similar:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file ' + filePath, e)
... pero esto pierde el rastro de la excepción interna!
Editar: me gustaría ver tanto los mensajes de excepción como los seguimientos de pila y correlacionar los dos. Es decir, quiero ver en la salida que la excepción X ocurrió aquí y luego la excepción Y allí, igual que lo haría en C #. ¿Es esto posible en Python 2.6? Parece que lo mejor que puedo hacer hasta ahora (según la respuesta de Glenn Maynard) es:
try:
ProcessFile(filePath)
except Exception as e:
raise Exception('Failed to process file' + filePath, e), None, sys.exc_info()[2]
Esto incluye tanto los mensajes como los rastreos, pero no muestra qué excepción ocurrió en qué parte del rastreo.
Respuestas:
Python 2
Es sencillo; Pase el rastreo como el tercer argumento para plantear.
Siempre haga esto cuando detecte una excepción y vuelva a plantear otra.
fuente
raise MyException(str(e)), ...
, etc.raise E() from tb
y.with_traceback(...)
raise
es el valor para pasar a la excepción (en caso de que el primer argumento sea una clase de excepción y no una instancia). Así que si quieres excepciones de intercambio, en lugar de hacerloraise MyException(str(e)), None, sys.exc_info()[2]
, es mejor utilizar esto:raise MyException, e.args, sys.exc_info()[2]
.from future.utils import raise_
yraise_(ValueError, None, sys.exc_info()[2])
.Python 3
En python 3 puedes hacer lo siguiente:
Esto producirá algo como esto:
fuente
raise ... from ...
de hecho, es la forma correcta de hacer esto en Python 3. Esto necesita más votos a favor.Nakedible
Creo que es porque desafortunadamente la mayoría de la gente todavía no usa Python 3.future
paquete para lograr esto: python-future.org/compatible_idioms.html#raising-exceptions Egfrom future.utils import raise_
yraise_(ValueError, None, sys.exc_info()[2])
.Python 3 tiene la
raise
...from
cláusula para encadenar excepciones. La respuesta de Glenn es excelente para Python 2.7, pero solo usa el rastreo de la excepción original y descarta el mensaje de error y otros detalles. Estos son algunos ejemplos en Python 2.7 que agregan información de contexto desde el alcance actual al mensaje de error de la excepción original, pero mantienen intactos otros detalles.Tipo de excepción conocido
Ese sabor de
raise
declaración toma el tipo de excepción como la primera expresión, los argumentos del constructor de la clase de excepción en una tupla como la segunda expresión y el rastreo como la tercera expresión. Si está ejecutando antes de Python 2.2, vea las advertencias ensys.exc_info()
.Cualquier tipo de excepción
Aquí hay otro ejemplo que tiene un propósito más general si no sabe qué tipo de excepciones podría tener que atrapar su código. La desventaja es que pierde el tipo de excepción y solo genera un RuntimeError. Tienes que importar el
traceback
módulo.Modificar el mensaje
Aquí hay otra opción si el tipo de excepción le permitirá agregarle contexto. Puede modificar el mensaje de la excepción y luego volver a subirlo.
Eso genera el siguiente seguimiento de pila:
Puede ver que muestra la línea donde
check_output()
se llamó, pero el mensaje de excepción ahora incluye la línea de comando.fuente
ex.strerror
vino? No puedo encontrar ningún éxito relevante para eso en los documentos de Python. ¿No debería serstr(ex)
?IOError
se deriva deEnvironmentError
@hheimbuerger, que proporciona los atributoserrorno
ystrerror
.Error
, por ejemplo, ValueError, en unaRuntimeError
capturaException
? Si reproduzco su respuesta para este caso, se pierde el seguimiento de la pila.En Python 3.x :
o simplemente
que se propagará
MyException
pero imprimirá ambas excepciones si no se maneja.En Python 2.x :
Puede evitar imprimir ambas excepciones eliminando el
__context__
atributo. Aquí escribo un administrador de contexto que lo usa para detectar y cambiar su excepción sobre la marcha: (consulte http://docs.python.org/3.1/library/stdtypes.html para ampliar cómo funcionan)fuente
e.__traceback__
atributo!No creo que pueda hacer esto en Python 2.x, pero algo similar a esta funcionalidad es parte de Python 3. De PEP 3134 :
Comparación con C #:
Tenga en cuenta también que Java, Ruby y Perl 5 tampoco admiten este tipo de cosas. Citando de nuevo:
fuente
Para una máxima compatibilidad entre Python 2 y 3, puede usar
raise_from
en lasix
biblioteca. https://six.readthedocs.io/#six.raise_from . Aquí está su ejemplo (ligeramente modificado para mayor claridad):fuente
Puede usar mi clase CausedException para encadenar excepciones en Python 2.x (e incluso en Python 3 puede ser útil en caso de que desee dar más de una excepción capturada como causa de una excepción recién planteada). Puede que esto te ayude.
fuente
¿Tal vez podrías obtener la información relevante y pasarla? Estoy pensando en algo como:
fuente
Asumiendo:
raise ... from
solución)puede usar una solución simple de los documentos https://docs.python.org/3/tutorial/errors.html#raising-exceptions :
La salida:
Parece que la pieza clave es la palabra clave "subir" simplificada que se encuentra sola. Eso volverá a aumentar la Excepción en el bloque excepto.
fuente