python - print - ¿Cómo volver a plantear una excepción en bloques try/except anidados?
try except python 3 print error (4)
Sé que si quiero volver a plantear una excepción, uso simple raise
sin argumentos en el bloque except
respectivo. Pero dado una expresión anidada como
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e # I''d like to raise the SomeError as if plan_B()
# didn''t raise the AlsoFailsError
¿Cómo puedo volver a subir el SomeError
sin romper el rastro de la pila? raise
solo sería en este caso volver a subir el AlsoFailsError
más reciente. ¿O cómo podría refactorizar mi código para evitar este problema?
Puede almacenar el tipo de excepción, el valor y el rastreo en variables locales y usar la forma de raise
de tres argumentos :
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
raise t, v, tb
En Python 3, el rastreo está almacenado en la excepción, por lo que raise e
hará lo (en su mayoría) correcto:
try:
something()
except SomeError as e:
try:
plan_B()
except AlsoFailsError:
raise e
El único problema con lo anterior es que producirá un SomeError
levemente engañoso que indica que SomeError
produjo al manejar AlsoFailsError
(debido a que raise e
dentro de Except AlsoFailsError
), donde de hecho ocurrió exactamente lo contrario: manejamos AlsoFailsError
al intentar recuperar de SomeError
. Para deshabilitar este comportamiento y obtener un rastreo que nunca menciona AlsoFailsError
, reemplace raise e
con raise e from None
.
Python 3.5 y sigs. adjunta la información de seguimiento al error de todos modos, por lo que ya no es necesario guardarlo por separado.
>>> def f():
... try:
... raise SyntaxError
... except Exception as e:
... err = e
... try:
... raise AttributeError
... except Exception as e1:
... raise err from None
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 9, in f
File "<stdin>", line 3, in f
SyntaxError: None
>>>
Según la sugerencia de Drew McGowen , pero ocupándose de un caso general (donde existe un valor de retorno s
), aquí hay una alternativa a la respuesta del usuario4815162342 :
try:
s = something()
except SomeError as e:
def wrapped_plan_B():
try:
return False, plan_B()
except:
return True, None
failed, s = wrapped_plan_B()
if failed:
raise
Incluso si la solución aceptada es correcta, es bueno apuntar a la biblioteca Six que tiene una solución Python 2 + 3, utilizando six.reraise
.
seis. reubicación ( exc_type , exc_value , exc_traceback = None)
Reordene una excepción, posiblemente con un traceback diferente. [...]
Entonces, puedes escribir:
import six
try:
something()
except SomeError:
t, v, tb = sys.exc_info()
try:
plan_B()
except AlsoFailsError:
six.reraise(t, v, tb)