Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Exception raised even when caught in try/except clause [duplicate]

In my code I want to catch an exception when it occurs, print some information abut the exception to the screen, and then end the script once I have done so. I tried to use something equivalent to the following code, but I don't understand why I get the traceback I do.

When executing:

try:
    1 / 0
except ZeroDivisionError:
    print("Exception: ZeroDivisionError")
    raise Exception

Console reads:

Exception: ZeroDivisionError
Traceback (most recent call last):
  File "<pyshell#19>", 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 "<pyshell#19>", line 5, in <module>
    raise Exception
Exception

I thought that if I catch the ZeroDivisionError, it would no longer be raised, and the only thing that would show is the raise Exception I do at the end, but both show in the console.

Why do they both show, and how do I alter the code so only the second shows, or is there a better way to achieve what I want?

like image 1000
user3873725 Avatar asked Sep 15 '14 13:09

user3873725


People also ask

How do you handle multiple exceptions with a single except clause?

You can also handle multiple exceptions using a single except clause by passing these exceptions to the clause as a tuple . except (ZeroDivisionError, ValueError, TypeError): print ( "Something has gone wrong.." ) Finally, you can also leave out the name of the exception after the except keyword.

Can you have multiple except clauses for one try?

A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same try statement.

Can one block of except statements handle multiple exception?

Can one block of except statements handle multiple exception? Answer: a Explanation: Each type of exception can be specified directly. There is no need to put it in a list.

How do I ignore a specific exception in Python?

Use pass to ignore an exception Within a try and except block, use pass in the except clause to indicate no action is required in handling the caught exception.


1 Answers

The console shows the context here; when an exception is raised from an exception handler, Python attaches the active exception as the __context__ attribute and Python shows that context later on if the new exception is not being handled. If you don't want the context to be shown, you need to supply a cause instead; you can supply an empty cause with with raise ... from None:

try:
    1 / 0
except ZeroDivisionError:
    print("Exception: ZeroDivisionError")
    raise Exception from None

Quoting the raise statement documentation:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed[...]

A similar mechanism works implicitly if an exception is raised inside an exception handler: the previous exception is then attached as the new exception’s __context__ attribute[...]

And from the Exceptions documentation:

When raising (or re-raising) an exception in an except clause __context__ is automatically set to the last exception caught; if the new exception is not handled the traceback that is eventually displayed will include the originating exception(s) and the final exception.

When raising a new exception (rather than using a bare raise to re-raise the exception currently being handled), the implicit exception context can be supplemented with an explicit cause by using from with raise:

raise new_exc from original_exc

The expression following from must be an exception or None. It will be set as __cause__ on the raised exception. Setting __cause__ also implicitly sets the __suppress_context__ attribute to True, so that using raise new_exc from None effectively replaces the old exception with the new one for display purposes (e.g. converting KeyError to AttributeError), while leaving the old exception available in __context__ for introspection when debugging.

The default traceback display code shows these chained exceptions in addition to the traceback for the exception itself. An explicitly chained exception in __cause__ is always shown when present. An implicitly chained exception in __context__ is shown only if __cause__ is None and __suppress_context__ is false.

like image 79
Martijn Pieters Avatar answered Sep 24 '22 11:09

Martijn Pieters