Discover How to Manage Exceptions With Python
As you saw in the chapter “Learn to Understand What Python Tells You,” exceptions are bugs that appear when your program does something that Python doesn’t like. Either Python doesn’t understand what you’re asking, or you’re asking it to do something impossible.
Whichever it is, the consequence is the same: the program stops. But you can prevent this from happening if you know how to manage exceptions.
To manage an exception in Python, use the instructions try
and except
like this:
try:
numerator = input("State the numerator")
denominator = input("State the denominator")
print(numerator/denominator)
except:
print(“There’s a problem with this operation”)
What’s going on here? The instruction that may generate an error is in the try
. If it doesn’t generate one, the program continues, and everything runs smoothly.
However, if it generates an exception, the instruction in except
will be executed, regardless of the type. This is because you haven’t specified a type after the except
keyword. Therefore, you receive a vague message that doesn’t tell you the cause of the error.
But what exceptions might occur in your operation? I can think of at least three:
ValueError: The user has entered something other than figures and decimal points
.
(i.e.,a
,$
, or10,5
,etc.).ZeroDivisionError: An error caused by a division by 0, which is mathematically impossible.
TypeError: The user tried to carry out an operation between a number and a string.
Here’s how to manage these cases:
try :
numerator = input("State the numerator")
denominator = input("State the denominator")
print(int(numerator)/int(denominator))
except (ZeroDivisionError, ValueError):
print("There’s a problem with the code")
As you can see, this time we caught the exceptions ZeroDivisionError
and ValueError
by providing an error message. We could have given a bit more detail, though! Let’s do that now:
try :
numerator = input("State the numerator")
denominator = input("State the denominator")
print(int(numerator)/int(denominator))
except ValueError:
print("ValueError: You must have written something other than numbers with or without a decimal point")
except ZeroDivisionError:
print("ZeroDivisionError: It looks like you’re trying to divide by zero—are you sure about that?")
except :
print("I’m not sure what’s happened—I can’t help, sorry!")
finally:
print("The instruction 'try except' was successfully executed!")
That’s better! There is now a message for each type of error. The last except
branch is displayed for all errors other than ValueError
and ZeroDivisionError
. The finally
branch runs at the end of the exception block, regardless of the type raised. It’s a concluding remark that always appears, whether things have gone smoothly or not!
But we can go one better! For the moment, we caught the exception but haven’t managed it. So let’s see how to do this now so the program can continue.
try :
numerator = input("State the numerator")
denominator = input("State the denominator")
print(int(numerator)/int(denominator))
except ValueError:
print("ValueError: You must have written something other than numbers with or without a decimal point\n
Try again!")
while True:
numerator = input("State the numerator. Please use only numbers and decimal points.")
denominator = input("State the denominator. Please use only numbers and decimal points.")
if (numerator.isdigit() and denominator.isdigit() and int(denominator) != 0):
break
print(int(numerator)/int(denominator))
except ZeroDivisionError:
print("ZeroDivisionError: It looks like you’re trying to divide by zero—are you sure about that?")
except :
print("I’m not sure what’s happened—I can’t help, sorry!")
finally:
print("The instruction 'try except' was successfully executed!")
Not only does the code above catch the exception ValueError
, but it fixes it to allow the program to continue.
For example, if your numerator or denominator contains something other than figures, a ValueError
is raised. You then enter an infinite loop that asks you to enter a new numerator and denominator. The loop will continue as long as these contain anything other than numbers. So let’s check that the denominator isn’t 0. And there you have it—the exception is caught and managed!
One last thing—you can also raise exceptions manually, which is handy if you want to apply a specific rule to your program to prevent something from happening.
For example, imagine you’re creating a program to check users’ passwords for entering a program. You could write this:
password = input("What’s the password?")
if password != "1234":
raise Exception("Intruder detected!")
else:
print("Welcome to the club!")
We raised an exception manually by using the keyword raise
.
We could also have chosen one of the built-in exceptions in Python, like this:
password = input("What’s the password?")
if password != "1234":
raise TypeError("The password should be a set of numbers. Intruder detected!")
else:
print("Welcome to the club!")
Manage Exceptions in Software and Web Projects
In the following screencast, you’ll see how to manage exceptions in our rock-paper-scissors project. I’ll do this for the software and web versions, starting with the tkinter project.
In this screencast, I caught the different exceptions generated by our program. To do this, place all the lines that may generate errors in try
and except
blocks. These errors were RuntimeError
, NameError
and_tkinter.TclError
.
The exception _tkinter.TclError
is a special case. It doesn’t belong to the standard Python library and can’t be used after the instruction except
unless imported from the tkinter
module. Another solution would be to not write anything after except
, which would catch all exceptions generated in the try
.
Now let’s move on to the web version with Flask!
In this screencast, you saw how to use the function abort
to link a specific route to an exception. You also saw how to link the decorator@app.errorhandler()
to a function to redirect a page generating an HTTP error to a specific template.
Finally, let’s move on to the Django version.
As you saw in the screencast, managing HTTP errors with Django is simple. All you have to do is create an HTML file with the target HTTP code as its name. This way, the user will be redirected to the HTML file template whenever an HTTP error with that specific code is generated.
Over to You!
Let’s finish with an exercise. The code below outputs a message to show a person’s age. Your task is to catch all possible exceptions and manage them, so the program continues running.
Here’s the code for the exercise:
from datetime import *
year_of_birth = int(input("What is your year of birth?"))
age = int(datetime.now().strftime("%Y")) - year_of_birth
print(f"You are {age} years old.")
Have a go, and then compare your work with mine in the GitHub repository.
Let’s Recap!
You can manage exceptions in a
try
andexcept
block.The
try
block contains the instruction that may raise an exception.The
except
block contains instructions if the exception is raised.You can provide the name of an exception (or an exception group) after the instruction
except
. If nothing is stated afterexcept
, it means it will apply to any exception raised.The instruction
finally
comes at the end of atry
andexcept
block, no matter the result.
Now you know how to manage exceptions; it’s high time to exterminate some bugs, don’t you think? If you agree, come with me to the next chapter!