Exceptions are events that can modify the flow of control through a Python application and are triggered when errors occur. When writing production code it’s a good idea to both intercept or “catch” exceptions and to throw or “raise” exceptions so you can make your application stop, warn the user, or perform another action if something goes wrong.
In Python, exception handling is achieved using try except
blocks, which are akin to the try catch
blocks of other languages, such as PHP. As the name suggests, the try
part attempts to run a block of code, while the except
block returns an exception if it fails.
In this project, I’ll show you the basics of using try/except
to catch Python exceptions and modify the flow of control in your applications when things go wrong. There’s quite a bit more you can do with Python exception handling, but this is plenty to get you started.
Firstly, let’s take a look at what happens when you don’t catch an exception in your Python program. In the below example, we’ll attempt to use the open()
function to open a file called exists.txt
which exists on my local machine. If it works, the code runs and no exception is returned and no error is displayed.
file = open('exists.txt')
If we repeat that process by attempting to run open()
on a file called missing.txt
that does not exist, Python will throw or “raise” an exception. As we’re not doing anything to catch this exception, it’s known as an uncaught exception.
Uncaught exceptions, while not an issue in a Jupyter notebook where you can fix the issue manually, can be problematic in production code and would cause execution to stop completely, effectively crashing the application.
That said, exceptions are very useful to programmers, since they return a “traceback”. The traceback tells you why the program failed and what specific type of exception was raised or thrown. In this example, it tells us that the issue lies with the line file = open('missing.txt')
which throws a FileNotFoundError
because no such file or directory exists.
file = open('missing.txt')
FileNotFoundErrorTraceback (most recent call last)
<ipython-input-2-3e55dded282a> in <module>
----> 1 file = open('missing.txt')
FileNotFoundError: [Errno 2] No such file or directory: 'missing.txt'
A try/except
block wraps up the call to the open()
command in a try
statement. Python will try to run the code and, if it works, the contents of the file will be stored in the file
variable and File exists
will be printed. If it fails, except
will run and raise an Exception
which prints File does not exist
.
try:
file = open('exists.txt')
print('File exists')
except Exception:
print('File does not exist')
File exists
try:
file = open('missing.txt')
print('File exists')
except Exception:
print('File does not exist')
File does not exist
As we saw in the first example, running open()
on a file that does not exist actually returns a FileNotFoundError
. By adding an additional except
block to catch the FileNotFoundError
we can display a more informative error to the user to explain that the code failed because the file does not exist.
Importantly, the bare Exception
at the end needs to follow any more specific exceptions above, otherwise it will simply say An error occurred
rather than show the more specific and useful error message.
There are a wide number of common Python exception types that you can incorporate into your code to catch specific exceptions by their type and then change the program flow accordingly, or show more useful error messages. In addition to these common exception types, many Python applications raise their own more specific exceptions that you may wish to incorporate into your code.
try:
file = open('exists.txt')
print('File exists')
except FileNotFoundError:
print('File does not exist')
except Exception:
print('An error occurred')
File exists
try:
file = open('missing.txt')
print('File exists')
except FileNotFoundError:
print('File does not exist')
except Exception:
print('An error occurred')
File does not exist
Another neat trick to making your exception messages more informative is to catch the exception message thrown and output that. For example, instead of using except FileNotFoundError: print('File does not exist')
, we can use except FileNotFoundError as e: print('File does not exist:', e)
. If you run the code below, you’ll see that this prints a more informative exception stating: File does not exist: [Errno 2] No such file or directory: 'missing.txt'
.
try:
file = open('exists.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
File exists
try:
file = open('missing.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
File does not exist: [Errno 2] No such file or directory: 'missing.txt'
The else
statement can also be added to a try/except
block to aid flow control. In the code example below, we try and run open()
and throw a FileNotFoundError
if it fails to find the file, and a general Exception
if something else goes wrong. If the file opens correctly, the else
statement will kick in and the file contents will be read and printed out.
try:
file = open('exists.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
else:
print(file.read())
file.close()
File exists
Here are the file contents.
try:
file = open('mising.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
else:
print(file.read())
file.close()
File does not exist: [Errno 2] No such file or directory: 'mising.txt'
The finally
statement is also a useful addition to the try/except
block. Unlike else
, which only runs if no exception is thrown, finally
will run whether there’s an exception or not. Here’s a quick example showing it in action.
try:
file = open('exists.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
else:
print(file.read())
file.close()
finally:
print('This bit always runs. Exception or not.')
File exists
Here are the file contents.
This bit always runs. Exception or not.
try:
file = open('missing.txt')
print('File exists')
except FileNotFoundError as e:
print('File does not exist:', e)
except Exception as e:
print('An error occurred:', e)
else:
print(file.read())
file.close()
finally:
print('This bit always runs. Exception or not.')
File does not exist: [Errno 2] No such file or directory: 'missing.txt'
This bit always runs. Exception or not.
Matt Clarke, Friday, December 24, 2021