Previous Lesson | Table of Contents | Next Lesson |
When code executes, errors can occur. For example, if you could have invalid syntax:
print("cat)
The string cat
is missing an ending quotation mark, leading to this error:
SyntaxError: EOL while scanning string literal
Here’s the error you get when you try to divide a number by zero:
ZeroDivisionError: division by zero
You sometimes might want to raise an error yourself. For example, suppose you have a function that doesn’t accept the input of 1, you could write something like this:
def f(x):
if x == 1:
raise ValueError("x cannot be 1")
print(x)
To raise an error yourself, use the raise keyword, followed by the name
of the error you want to raise (in this case, ValueError
) and pass in it
the error message you want to provide. Thus, when you execute something like
the following:
f(1)
print("Program continued!")
We get:
ValueError: x cannot be 1
Although error message like these are useful, one disadvantage is that they
halt the execution of your code (notice how the print
statement below did
not execute). What if this error was not really that critical, and you wanted
to proceed with the rest of your code? This is where the concept of
try-except
comes in:
try:
f(1)
except ValueError:
print("Function errored, but let's continue!")
print("Program continued!")
This gets us now:
Function errored, but let's continue!
Program continued!
Unlike before, we now get to the final print
statement because we handled
the error raised through this except
statement and did not halt the program.
The purpose of the try-except
format is to give us the possibility of guarding
against potential errors that could halt our program. If no such errors occur,
the code executes as normal. For example, if we had tried:
try:
f(2)
except ValueError:
print("Function errored, but let's continue!")
print("Program continued!")
Passing in 2
to f
does not raise an error, so this gets us:
2
Program continued!
When we have a try-except
statement, we can have multiple except
blocks
for a single try
, just like we could have multiple elif
blocks for a single
if
statement. Python checks each except
block from top to bottom, checking
to see if the error being handled matches the one that is raised. For example:
try:
f(2)
except TypeError:
print("Function errored strangely, but let's continue anyhow!")
except ValueError:
print("Function errored, but let's continue!")
print("Program continued!")
Note that if the error does not match to any of the ones provided, the error is raised and halts the program as before:
try:
f(2)
except TypeError:
print("Function errored, but let's continue!")
print("Program continued!")
We get the same error message as before and abort before getting to the
last print
statement, as the error is a ValueError
, not TypeError
:
ValueError: x cannot be 1
Finally, it should be noted that if we just have a bare except
(i.e. one
without any error name after it), it is considered a “catch-all” and can be
used to handle any error raised.
try:
f(2)
except TypeError:
print("Function errored, but let's continue!")
except:
print("Catch all saves the day!")
print("Program continued!")
This will output:
Catch all saves the day!
Program continued!
Although the name Exception
might have a negative connotation, exceptions
are very useful in terms of adding more sophistication to the code that you write
by providing a true mechanism for handling errors or invalid inputs provided.
That’s it for now! Let’s answer questions to review what we learned:
How would you raise an
OSError
with the message: “Sorry about that! Something went wrong” ? (solution).Create a function that accepts one argument. Have the function print
"Good input!"
, unless the argument is"cat"
, in which case, raise aValueError
(solution).Create a
try-except
block with your function by calling it with the argument"cat"
in thetry
block. In theexcept
block, have it print anything that you want. After thetry-except
, print something else (solution).
By the way, you may have noticed that error types are in fact classes, and their
__init__
functions almost always accept an optional parameter for the
error message that is displayed to users.
Finally, although this lesson presents only a few errors, we have seen several
others throughout, including NameError
(Lesson 3)
and IndexError
(Lesson 6).
If you are comfortable with errors, feel free to move on to imports.