CHAPTER 10
Handling Errors
In this chapter, you learn how to handle errors in Python. First, we quickly review the different types of errors that occur in computer code and the ways you can catch the different types. We then focus on using try… except
blocks to handle errors in your Python code. You learn to cause errors, trap exceptions, and create custom exceptions.
Understanding the Various Types of Errors
Cause Errors and Trap Exceptions
Add an else
Block or a finally
Block
Understanding the Various Types of Errors
In this section, you learn about the different types of errors that can occur in code, what causes them, and what you can do to eliminate them.
We start with compile-time errors, errors that occur when Python is unable to create workable instructions from the commands in a script. Many compile-time errors are syntax errors, mistakes in the structure of the code. We then move on to runtime errors, errors that occur after Python has compiled a script successfully and has moved on to executing it. Runtime errors include semantic errors and logical errors.
Compile-Time Errors
Python is generally considered an interpreted language, which is often understood to mean that it is not a compiled language. But the difference between interpreted computing languages and compiled computing languages is not clear cut, and Python does perform compilation.
Before running a script, Python compiles it to a form called byte code, interpreting the commands the script contains and creating from them instructions that the computer can execute. The instructions need to be specific to the computer’s operating system, such as Windows or macOS, and to the processor type, such as Intel or Apple Silicon.
A compile-time error occurs when the script’s commands are incomplete, incorrect, or otherwise will not work. A compile-time error occurs before the script runs, so Python does not run the script. You need to fix the problem in order to make the script run.
Runtime Errors
After compiling the code in the script, Python tells the computer to run the script. At this point, you may get a runtime error — an error that occurs while the code is running, as opposed to while the code is being compiled.
A runtime error may manifest itself as an exception that stops the script from running and causes Python to display an error message. Alternatively, the script may freeze or crash, it may return an unexpected result, or it may damage data.
Syntax Errors
A syntax error, also called a syntactical error, is an error where the problem lies in the structure of the code statements. Syntax errors have various causes, including the following:
firstname
when you mean to reassign the existing variable firstName
Python itself or your code editor may be able to identify a syntax error for you. For example, the illustration shows Python flagging the cause of a syntax error in the following statement, which contains an extra comma after the "Bill"
item in the list. The caret (A) points to the problem, and the SyntaxError
statement (B) briefly explains what is wrong.
a = ["Ann", "Bill",, "Chris"]
Semantic Errors
A semantic error is an error in which your code is syntactically correct but does not execute the way you intend it to. The word semantic means “related to meaning in language or logic” — in other words, the meaning of the code is wrong.
For example, if a script gets stuck in an infinite loop because the break
statement you included never gets triggered, you have likely committed a semantic error. Similarly, if a while
loop never runs because its condition cannot be met, that might be a semantic error.
Your code editor or IDE will typically not catch semantic errors. Instead, you will normally discover them while testing and debugging your scripts.
How you discover semantic errors will vary depending on the error’s effects. Continuing the previous example, you will notice an infinite loop quickly, because the script will not finish and you will need to break out of the loop. By contrast, a while
loop that never runs may be less obvious.
Logical Errors
A logical error occurs when you, the developer, have told the script to take the wrong action. Even though the script is syntactically correct and semantically correct, what the script does is incorrect. For example, a logical error might occur if you make a mistake with operator precedence when performing calculations or if you use integer division where you should use floating-point division.
Identify Common Python Errors
Python includes a wide variety of built-in exceptions for handling types of errors that occur frequently. For example, a SyntaxError
error occurs when Python’s parser encounters syntax it cannot convert into valid code, such as when you omit a comma or include an extra parenthesis. A TypeError
error occurs when the code specifies the wrong type of object for an operation, such as trying to add an integer and a string. A ValueError
error occurs when the code specifies the correct type of object but an incorrect value, such as trying to return the square root of a negative number.
Table 10-1 explains common error types in Python.
Table 10-1: Common Errors in Python
Exception |
Occurs When |
---|---|
|
An |
|
An attribute assignment or attribute reference is incorrect. |
|
The |
|
An error occurs in a floating-point calculation. |
|
Code calls the |
|
Importing the specified module fails. |
|
The index number of a sequence is out of range. |
|
The specified key is not in the dictionary. |
|
The user gave a keyboard interrupt by pressing + or . |
|
An operation runs out of memory. |
|
Python cannot find the specified module. |
|
The specified variable is not found. |
|
An abstract method requires a derived class to override the method; or a developer uses this error as a placeholder to show a real implementation is still needed. |
|
An operating system–related error occurs. |
|
An arithmetic operation returns an error too large to represent. |
|
A weak reference proxy accesses an attribute of an item that has been garbage collected. |
|
A runtime error occurs that does not fall into any other category. |
|
The |
|
The parser encounters a syntax error. |
|
The indentation level of a statement is incorrect — for example, some indentation is missing. |
|
The indentation consists of a mixture of tabs and spaces instead of only tabs or only spaces. |
|
An internal error occurs in the Python interpreter. |
|
The |
|
An object is of the wrong type for the specified operation. |
|
A function or method refers to a local variable that has no value. |
|
Encoding or decoding Unicode characters causes an error. |
|
Encoding Unicode characters causes an error. |
|
Decoding Unicode characters causes an error. |
|
A Unicode-related error occurs during translation. |
|
An argument passed to a function or method has the correct type but an incorrect value. |
|
Division or modulo by zero is attempted. |
Meet the try… except
Block
Python uses a type of object called an exception to handle errors. Python includes many built-in exceptions, which are all derived from the same base class of exception. For example, using the wrong name may cause a NameException
exception, whereas supplying the wrong kind of value may cause a ValueException
exception.
When an error occurs, Python raises or throws an exception. You can catch or trap an exception so that you can determine what has gone wrong and do something about it.
Python’s tool for handling exceptions is the try… except
block, which looks like the following pseudocode. Italics indicate placeholders, and the sections in brackets are optional.
try:
statements1
[except error:
statements2]
except:
statements3
[else:
statements4]
[finally:
statements5]
Here is how the try… except
block works:
try:
. This keyword starts the try
block.statements1
. This block contains one or more statements that may cause an exception. The try
block is said to wrap these statements.except error:
. The except
keyword starts an except
block for the specified error. For example, except NameError:
starts an except
block that controls what happens when a NameError
error occurs.statements2
. This block contains one or more statements to run when the specified error occurs.except:
. The except
keyword without a specific error starts an except
block for any error.statements3
. This block contains one or more statements to run when any error occurs.else:
. The else
keyword starts a block specifying what to do if no error has occurred.statements4
. This block contains one or more statements to run if no error has occurred.finally:
. This keyword starts a block specifying what to do after the rest of the try… except
block has completed, whether an error has occurred or not.statements5
. This block contains one or more statements to run after execution reaches the finally
keyword.The following subsections contain brief examples of try… except
blocks.
Trap Any Exception
If you just want to trap any exception that Python raises, you can use a plain except
statement, as in the following example:
try:
x = 5/0
except:
print("An error occurred.")
Trap One or More Particular Exceptions
A generic error message offers little help, so you will often do better to trap one or more specific exceptions that are likely to occur, as in the following example:
try:
x = 5/0
except(NameError):
print("A name is missing.")
except(ZeroDivisionError):
print("A divide-by-zero error occurred.")
except:
print("An error occurred.")
This example contains three except
blocks:
except(NameError):
. This block catches NameError
, the type of error that occurs when your code specifies an item that does not exist.except(ZeroDivisionError):
. This block catches ZeroDivisionError
, the error that occurs when your code tries to divide by zero. As the code stands, the x = 5/0
statement triggers a ZeroDivisionError
error.except:
. This block catches any other errors.The unqualified except
block must be the last except
statement in the try… except
block. You cannot use except
with a specific error after an unqualified except
block. Doing so causes the error SyntaxError: default 'except:' must be last
.
Add an else
Block
Python supports adding an else
block to a try… except
block. Here is an example:
try:
x = 5/0
except:
print("An error occurred.")
else:
print("No error occurred.")
An else
block can be useful, but many try… except
blocks do not need one.
Add a finally
Block
You can include a finally
block in your try… except
blocks to specify an action that Python should always perform, whether or not an exception has occurred. Here is an example:
try:
x = 5/0
except:
print("An error occurred.")
finally:
print("The try block has finished.")
Cause Errors and Trap Exceptions
In this section, you cause errors in your code deliberately and observe the exceptions that Python throws as a result. You then handle the exceptions by using try… except
blocks. The first try… except
block you create is generic, returning the same error message for every exception it catches. After that, you create a more sophisticated try… except
block that displays specific error messages for the exceptions you raised earlier, plus a generic error message for any other exception.
Cause Errors and Trap Exceptions
Cause Errors and Create a Generic Exception Trap
Open a terminal window and launch Python.
The Python prompt appears.
Type the following statement, which creates the variable x
and assigns to it the result of 5
divided by 0
. Press .
x = 5/0
An error occurs.
Python displays the exception for the error:
ZeroDivisionError: division by zero
Type the following statement, which assigns to x
the value of variable y
, and then press .
x = y
An error occurs, because y
does not yet exist.
Python displays the exception for the error:
NameError: name 'y' is not defined
Type the following try… except
block, which uses a single unspecified exception. Press at the end of each line, and press again at the end.
try:
x = 5/0
except:
"An error occurred."
Python returns 'An error occurred.'
because the try
block catches the error.
Trap Specific Errors
In the same terminal window, type the following try… except
block, which includes specific messages for the ZeroDivisionError
exception and the NameError
exception you raised earlier. Press at the end of each line.
try:
x = 5/0
except(ZeroDivisionError):
"A divide-by-zero error occurred."
except(NameError):
"A name is missing."
except:
"An error occurred."
Press to end the block.
Python returns the message 'A divide-by-zero error occurred.'
, because except(ZeroDivisionError)
catches the error.
Type the same try… except
block, but this time include x = y
to produce the NameError
exception. Press at the end of each line.
try:
x = y
except(ZeroDivisionError):
"A divide-by-zero error occurred."
except(NameError):
"A name is missing."
except:
"An error occurred."
Press to end the block.
Python returns the message 'A name is missing.'
, because the except(NameError)
catches the error.
Raise an Exception Manually
In the previous section, “Cause Errors and Trap Exceptions,” you caused the ZeroDivisionError
and NameError
errors deliberately by entering statements guaranteed not to work. This approach is straightforward for some errors, but you might need to get creative to produce other errors. So Python offers an alternative: You can raise specific exceptions manually to test your code.
To raise an exception, you use the raise
command and specify the type of exception — for example, raise Exception
or raise RuntimeError
. You can also specify the text to display to the user when the exception or error is raised.
Raise an Exception Manually
Raise an Exception Outside of a try… except
Block
Open a terminal window and launch Python.
The Python prompt appears.
Type the following statement, which uses the raise
keyword to raise a ValueError
error with a custom message. Press .
raise ValueError("This value is not valid.")
Python returns the following:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: This value is not valid.
Raise an Exception Inside of a try… except
Block
Still in the same terminal window and Python session, type the following try
block, which contains a statement that raises a TypeError
. Press at the end of each line.
try:
raise TypeError
Type the following except
block, which catches the TypeError
exception. Press at the end of each line, and then press again to end the block.
except TypeError:
print("A TypeError exception has occurred.")
Python displays the resulting message:
A TypeError exception has occurred.
Add an else
Block or a finally
Block
You can add an else
block to a try… except
block to execute statements when no exception has occurred. You can also add a finally
block containing statements that you want to execute when the try… except
block has finished running, whether or not any exception arises. This section shows a finally
block that displays information, but the block can be useful for performing cleanup operations, such as closing files.
Add an else
Block or a finally
Block
Open a terminal window and launch Python.
Type the following try
block, which creates the variable n
and assigns 51
to it; creates the variable d
and assigns the user’s input divisor, cast to an integer; and creates the variable msg
and assigns a message to it.
try:
n = 51
d = int(input("Enter the integer divisor: "))
msg = str(n) + " divided by " + str(d) + " equals " + str(n/d)
Type the following except
block to handle a potential ZeroDivisionError
exception:
except ZeroDivisionError:
msg = "You cannot divide by zero."
Type the following finally
block, which displays the contents of msg
:
finally:
print(msg)
Press again to end the block.
Type an integer at the prompt.
The result appears.
Create Nested try… except
Blocks
Python enables you to nest try… except
blocks inside other try… except
blocks. Nesting blocks enables you to perform more complex error handling.
If an exception is raised in the outer try… except
block, the outer block handles the exception. If the inner try… except
block raises an exception, the inner block handles the exception; if it fails to do so — for example, because it has no unqualified except
statement — the outer block takes over responsibility for handling the exception.
Create Nested try… except
Blocks
Open Visual Studio Code and create a new Python script.
Type the following statement, which creates a variable called adrFile
and assigns to it the file addresses.csv
. Press .
adrFile = "addresses.csv"
Type the following statement, which creates a variable named addresses
and assigns to it an empty list. Press .
adrs = []
Type the following try
block, which uses the open()
function to open addressFile
in Read Mode. Press .
try:
f = open("adrFile", "r")
At the same level of indentation, type the nested try
block, which uses two for
loops to iterate through the lines in f
, split the addresses at the commas, and assign the resulting fields to the adrs
list. Press at the end of each line.
try:
for line in f.readlines():
currAdr=[]
for field in line.strip('
').split(','):
currAdr.append(field)
adrs.append(currAdr)
Indented to the level of the inner try
block, type the inner except
block, which uses the print()
function to display an error message. Press at the end of each line.
except:
print("An error occurred in the inner try… except block.")
Press twice to remove the indent, and then type the following except
block, which runs if the FileNotFoundError
occurs. Press at the end of each line.
except FileNotFoundError:
print(f"The file '{adrFile}' was not found.")
Press to remove the indent again, and then type the following unqualified except
block, pressing at the end of each line.
except:
print("An error occurred in the outer try… except block.")
Press to remove the indent once more, and then type the following else
block, which closes f
and displays the addresses. Press at the end of each line.
else:
f.close()
print(adrs)
Click Run Python File in Terminal ().
The Terminal pane appears.
A FileNotFoundError
occurs, because addresses.csv
does not exist.
The except FileNotFoundError:
block catches the exception.
The error message appears.
Create a file named addresses.csv
containing address information in the folder Python is using. Put each address on one line, with commas separating the fields.
Click Run Python File in Terminal ().
The address information appears.
Create Custom Exceptions
As you have seen earlier in this chapter, Python includes a wide range of built-in exceptions. But Python also lets you create your own custom exceptions, which enables you to track exactly what is going wrong in your code.
To create custom exceptions, you create a class based on Python’s base class of exceptions. You can then use a raise
statement to raise instances of the exception, assigning a custom error message to make clear the problem to the user. See Chapter 12, “Working with Classes,” for more information on classes.
Create Custom Exceptions
Open Visual Studio Code and create a new Python script.
Type the following class header, which creates a class named InvalidTitle
based on the Exception
object.
class InvalidTitle(Exception):
Type the pass
keyword as the only statement for the class, allowing the code to run without taking any action. Press twice, creating a blank line.
pass
Press to delete the indent, and then type the start of a try
block. Press .
try:
Type the following statement, which creates a variable named title
and assigns to it the result of the input()
function prompting the user to enter the title. Press .
title = input("Type the title: ")
Type the following if
block, which uses the isnumeric()
method to check whether title
is entirely numeric and, if so, raises an InvalidTitle
instance with a custom error message. Press at the end of each line.
if title.isnumeric():
raise InvalidTitle("The title is entirely numeric.")
Press to remove one step of indentation, and then type the following two elif
blocks, which use the len()
function to check the length of title
and raise InvalidTitle
instances if it is too short or too long:
elif len(title) < 5:
raise InvalidTitle("The title is too short.")
elif len(title) > 50:
raise InvalidTitle("The title is too long.")
Press once, and then type the following two elif
blocks, which raise InvalidTitle
instances for all uppercase and all lowercase:
elif title.isupper():
raise InvalidTitle("The title is all uppercase.")
elif title.islower():
raise InvalidTitle("The title is all lowercase.")
Press twice to remove the indentation, and then type the following except
statement, which casts an InvalidTitle
exception to IT
and prints that object:
except InvalidTitle as IT:
print(IT)
Press once to remove the indent, and then type the following if
block, which displays title
if no exception has been raised:
else:
print(title)
Click Run Python File in Terminal ().
The Terminal pane appears.
When prompted, type a title.
If the title provokes an exception, the relevant message appears.
13.58.82.83