Hay una nueva característica que se introdujo en python3: el encadenamiento de excepciones. Por algunas razones, necesito deshabilitarlo para ciertas excepciones en mi código.
Aquí está el código de muestra:
try: print(10/0) except ZeroDivisionError as e: sys.exc_info() raise AssertionError(str(e))
lo que veo:
Traceback (most recent call last): File "draft.py", line 19, in main print(10/0) ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "draft.py", line 26, in main() File "draft.py", line 22, in main raise AssertionError(str(e)) AssertionError: division by zero
lo que quiero ver:
Traceback (most recent call last): File "draft.py", line 26, in main() File "draft.py", line 22, in main raise AssertionError(str(e)) AssertionError: division by zero
Intenté usar sys.exc_clear()
, pero este método también se elimina de python 3. Puedo usar una solución que funcione
exc = None try: print(10/0) except ZeroDivisionError as e: exc = e if exc: raise AssertionError(str(exc))
Pero creo que hay mejor solución.
try: print(10/0) except ZeroDivisionError as e: raise AssertionError(str(e)) from None
Sin embargo, probablemente quieras:
try: print(10/0) except ZeroDivisionError as e: raise AssertionError(str(e)) from e
__cause__
El encadenamiento de excepciones implícito ocurre a través de __context__
cuando no hay un conjunto de excepciones de causas explícitas.
El encadenamiento de excepciones explícito funciona a través de __cause__
por lo tanto, si establece __cause__
en la excepción misma, debería detener el encadenamiento. Si se establece __cause__
, Python suprimirá el mensaje implícito.
try: print(10/0) except ZeroDivisionError as e: exc = AssertionError(str(e)) exc.__cause__ = exc raise exc
Podemos usar “subir desde” para hacer lo mismo:
try: print(10/0) except ZeroDivisionError as e: exc = AssertionError(str(e)) raise exc from exc
__cause__
Establecer __cause__
en None
realidad hace lo mismo:
try: print(10/0) except ZeroDivisionError as e: exc = AssertionError(str(e)) exc.__cause__ = None raise exc
Así que eso nos lleva a la forma más elegante de hacer esto, que es elevar desde None
:
try: print(10/0) except ZeroDivisionError as e: raise AssertionError(str(e)) from None
Pero diría que normalmente desea elevar explícitamente su excepción de la excepción de causa para que se conserve el rastreo:
try: print(10/0) except ZeroDivisionError as e: raise AssertionError(str(e)) from e
Esto nos dará un mensaje ligeramente diferente que indica que la primera excepción fue la causa directa de la segunda:
Traceback (most recent call last): File "", line 2, in ZeroDivisionError: division by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "", line 4, in AssertionError: division by zero