Deshabilitar el encadenamiento de excepciones en python 3

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.

Related of "Deshabilitar el encadenamiento de excepciones en python 3"

Respuesta simple

 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 

Explicación

__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 

subir desde

Podemos usar “subir desde” para hacer lo mismo:

 try: print(10/0) except ZeroDivisionError as e: exc = AssertionError(str(e)) raise exc from exc 

Ninguna __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 

subir de Ninguno

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