As mentioned previously, exceptions occur at runtime when some form of unexpected action takes place. There are plenty of built-in exceptions in Python that are raised when corresponding errors occur, and we can view these by using the built-in local() function as follows:
print(dir(locals()['__builtins__']))
Below are a few common exceptions we may come across.
When an error occurs in Python, it generates an exception object that describes the error and stops the normal execution of the program. You may notice that the program executes all of the code leading up to the exception, but then does not execute anything past the line of code where the exception occurs. An easy way that we handle these exceptions as they occur so that they do not disrupt the execution of the code is by using a try-except block.
try:
# code that may raise an exception
except ExceptionType:
# code to handle the exception
Notice in the above syntax that we can put any block of code we want inside the try block. If that codes executes without any issues, nothing will happen after that block is executed. If, however, any kind of exception occurs, we can choose to handle it inside the except block in a way other than spitting out the ugly error message we’re used to seeing.
Consider an example where we try to divide by zero:
try:
x = 1 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
# Rather than halt the code and print out this:
# ----------------------------------
# Traceback (most recent call last):
# File "main.py", line 1, in
# x = 1 / 0
#ZeroDivisionError: division by zero
# We can print out this, and keep moving in our code:
# ----------------------------------
# Cannot divide by zero
We know that the second line will give us a ZerioDivisionError because we cannot divide 1 by 0. As a result, we choose to print out a simple message saying you cannot divide by zero, rather than allowing the program to throw the exception and halt everything afterwards in the code.
Consider a few other useful exceptions we may want to account for:
try:
x = "5"
y = 2
result = x / y
except TypeError:
print("You cannot divide an string by an integer")
print("Double check your data types")
try:
fruits = ["apples", "oranges", "bananas"]
print(fruits[3])
except IndexError:
print("You tried to access an index in the list that doesn't exist")
In addition to the try and except blocks, we can also include an optional finally block at the end that will automatically execute, regardless of if an exception was raised or not.
try:
f = open("myfile.txt")
# do something with the file
except IOError:
print("Error opening file")
finally:
f.close()
The finally block acts as cleanup code. Although it optional to include after try-except blocks, it does help maintain organization within your code.
In Python, you can also create or “raise” your own exceptions. The simplest format is to use the keyword raise followed by the name of a custom exception.
try:
# processing code
if something_special_happened:
raise MyException
except MyException:
print("something happened")
This allows the programmer to take into account any custom cases that you may want to trigger as an exception. As a practical example, consider you have a variable age that needs to be no less than 13 years old in order to access something. You might consider the following:
try:
# processing code
age = int(input("How old are you? "))
if age < 13:
raise TooYoungException
except TooYoungException:
print("Sorry, you must be 13 years or older.")