Errors detected during execution are called exceptions and are not unconditionally fatal. Most exceptions are not handled by programs; it is possible to write programs that handle selected exceptions. There are specific features in Python to deal with exceptions and exception logic. Furthermore, exceptions have a rich type hierarchy, all inheriting from the
- raise exception
- raise # re-raise an exception that’s already been raised
- raise exception from cause # Python 3 - set exception cause
- raise exception from None # Python 3 - suppress all exception context
- except [exception types] [ as identifier ]:
try...except: to catch exceptions. You should specify as precise an exception as you can:
The exception class that is specified - in this case,
ZeroDivisionError - catches any exception that is of that class or of any subclass of that exception.
ZeroDivisionError is a subclass of
And so, the following will still catch the
Catching multiple exceptions
There are a few ways to catch multiple exceptions.
The first is by creating a tuple of the exception types you wish to catch and handle in the same manner. This example will cause the code to ignore
If you wish to handle different exceptions in different ways, you can provide a separate exception block for each type. In this example, we still catch the
AttributeError, but handle the exceptions in different manners.
Chain exceptions with raise from
In the process of handling an exception, you may want to raise another exception. For example, if you get an
IOError while reading from a file, you may want to raise an application-specific error to present to the users of your library, instead.
You can chain exceptions to show how the handling of exceptions proceeded:
Creating custom exception types
Create a class inheriting from
or another exception type:
Do not catch everything!
While it's often tempting to catch every
Or even everything (that includes
BaseException and all its children including
In most cases it's bad practice. It might catch more than intended, such as
MemoryError - each of which should generally be handled differently than usual system or logic errors. It also means there's no clear understanding for what the internal code may do wrong and how to recover properly from that condition. If you're catching every error, you wont know what error occurred or how to fix it.
This is more commonly referred to as 'bug masking' and should be avoided. Let your program crash instead of silently failing or even worse, failing at deeper level of execution. (Imagine it's a transactional system)
Usually these constructs are used at the very outer level of the program, and will log the details of the error so that the bug can be fixed, or the error can be handled more specifically.
Code in an else block will only be run if no exceptions were raised by the code in the
try block. This is useful if you have some code you don’t want to run if an exception is thrown, but you don’t want exceptions thrown by that code to be caught.
Note that this kind of
else: cannot be combined with an
if starting the else-clause to an
elif. If you have a following
if it needs to stay indented below that
Exception handling occurs based on an exception hierarchy, determined by the inheritance structure of the exception classes.
OSError are both subclasses of
EnvironmentError. Code that catches an
IOError will not catch an
OSError. However, code that catches an
EnvironmentError will catch both
The hierarchy of built-in exceptions:
Exceptions are Objects too
Exceptions are just regular Python objects that inherit from the built-in
BaseException. A Python script can use the
raise statement to interrupt execution, causing Python to print a stack trace of the call stack at that point and a representation of the exception instance. For example:
which says that a
ValueError with the message
'Example error!' was raised by our
failing_function(), which was executed in the interpreter.
Calling code can choose to handle any and all types of exception that a call can raise:
You can get hold of the exception objects by assigning them in the
except... part of the exception handling code:
A complete list of built-in Python exceptions along with their descriptions can be found in the Python Documentation: https://docs.python.org/3.5/library/exceptions.html. And here is the full list arranged hierarchically: Exception Hierarchy.
Practical examples of exception handling
Imagine you want a user to enter a number via
input. You want to ensure that the input is a number. You can use
except for this:
Note: Python 2.x would use
raw_input instead; the function
input exists in Python 2.x but has different semantics. In the above example,
input would also accept expressions such as
2 + 2 which evaluate to a number.
If the input could not be converted to an integer, a
ValueError is raised. You can catch it with
except. If no exception is raised,
break jumps out of the loop. After the loop,
nb contains an integer.
Imagine you are iterating over a list of consecutive integers, like
range(n), and you have a list of dictionaries
d that contains information about things to do when you encounter some particular integers, say skip the
d[i] next ones.
KeyError will be raised when you try to get a value from a dictionary for a key that doesn’t exist.
If your code encounters a condition it doesn't know how to handle, such as an incorrect parameter, it should raise the appropriate exception.
Sometimes you want to catch an exception just to inspect it, e.g. for logging purposes. After the inspection, you want the exception to continue propagating as it did before.
In this case, simply use the
raise statement with no parameters.
Keep in mind, though, that someone further up in the caller stack can still catch the exception and handle it somehow. The done output could be a nuisance in this case because it will happen in any case (caught or not caught). So it might be a better idea to raise a different exception, containing your comment about the situation as well as the original exception:
But this has the drawback of reducing the exception trace to exactly this
raise while the
raise without argument retains the original exception trace.
In Python 3 you can keep the original stack by using the
Running clean-up code with finally
Sometimes, you may want something to occur regardless of whatever exception happened, for example, if you have to clean up some resources.
finally block of a
try clause will happen regardless of whether any exceptions were raised.
This pattern is often better handled with context managers (using the