31. Exceptions

When something goes wrong with your program, do you want to keep the user from seeing a red Python error message? Do you want to keep your program from hanging? If so, then you need exceptions.

Exceptions are used to handle abnormal conditions that can occur during the execution of code. Exceptions are often used with file and network operations. This allows code to gracefully handle running out of disk space, network errors, or permission errors.

31.1. Vocabulary

There are several terms and phrases used while working with exceptions. Here are the most common:

  • Exception: This term could mean one of two things. First, the condition that results in abnormal program flow. Or it could be used to refer to an object that represents the data condition. Each exception has an object that holds information about it.

  • Exception handling: The process of handling an exception to normal program flow.

  • Catch block or exception block: Code that handles an abnormal condition is said to “catch” the exception.

  • Throw or raise: When an abnormal condition to the program flow has been detected, an instance of an exception object is created. It is then “thrown” or “raised” to code that will catch it.

  • Unhandled exception or Uncaught exception: An exception that is thrown, but never caught. This usually results in an error and the program ending or crashing.

  • Try block: A set of code that might have an exception thrown in it.

Most programming languages use the terms “throw” and “catch.” Unfortunately Python doesn’t. Python uses “raise” and “exception.” We introduce the throw/catch vocabulary here because they are the most prevalent terms in the industry.

31.2. Exception Handling

The code for handling exceptions is simple. See the example below:

Handling division by zero
1# Divide by zero
3    x = 5 / 0
5    print("Error dividing by zero")

On line two is the try statement. Every indented line below it is part of the “try block.” There may be no unindented code below the try block that doesn’t start with an except statement. The try statement defines a section of code that the code will attempt to execute.

If there is any exception that occurs during the processing of the code the execution will immediately jump to the “catch block.” That block of code is indented under the except statement on line 4. This code is responsible for handling the error.

A program may use exceptions to catch errors that occur during a conversion from text to a number. For example:

Handling number conversion errors
1# Invalid number conversion
3    x = int("fred")
5    print("Error converting fred to a number")

An exception will be thrown on line 3 because “fred” can not be converted to an integer. The code on line 5 will print out an error message.

Below is an expanded version on this example. It error-checks a user’s input to make sure an integer is entered. If the user doesn’t enter an integer, the program will keep asking for one. The code uses exception handling to capture a possible conversion error that can occur on line 5. If the user enters something other than an integer, an exception is thrown when the conversion to a number occurs on line 5. The code on line 6 that sets number_entered to True will not be run if there is an exception on line 5.

Better handling of number conversion errors
1number_entered = False
2while not number_entered:
3    number_string = input("Enter an integer: ")
4    try:
5        n = int(number_string)
6        number_entered = True
7    except:
8        print("Error, invalid integer")

Files are particularly prone to errors during operations with them. A disk could fill up, a user could delete a file while it is being written, it could be moved, or a USB drive could be pulled out mid-operation. These types of errors may also be easily captured by using exception handling.

Checking for an error when opening a file
1# Error opening file
3    my_file = open("myfile.txt")
5    print("Error opening file")

Multiple types of errors may be captured and processed differently. It can be useful to provide a more exact error message to the user than a simple “an error has occurred.”

In the code below, different types of errors can occur from lines 3-15. By placing IOError after except on line 19, only errors regarding Input and Output (IO) will be handled by that code. Likewise line 21 only handles errors around converting values, and line 23 covers division by zero errors. The last exception handling occurs on line 25. Since line 25 does not include a particular type of error, it will handle any error not covered by the except blocks above. The “catch-all” except must always be last.

Handling different types of errors
 1# Multiple errors
 3    # Open the file
 4    filename = "myfile.txt"
 5    my_file = open(filename)
 7    # Read from the file and strip any trailing line feeds
 8    my_line = my_file.readline()
 9    my_line = my_line.strip()
11    # Convert to a number
12    my_int = int(my_line)
14    # Do a calculation
15    my_calculated_value = 101 / my_int
17except FileNotFoundError:
18    print(f"Could not find the file '{filename}'.")
19except IOError:
20    print(f"Input/Output error when accessing the file '{filename}'.")
21except ValueError:
22    print("Could not convert data to an integer.")
23except ZeroDivisionError:
24    print("Division by zero error.")
26    print("Unexpected error.")

A list of built-in exceptions is available from this web address:


31.3. Example: Saving High Score

This shows how to save a high score between games. The score is stored in a file called high_score.txt.

 2Show how to use exceptions to save a high score for a game.
 4Sample Python/Pygame Programs
 5Simpson College Computer Science
10def get_high_score():
11    # Default high score
12    high_score = 0
14    # Try to read the high score from a file
15    try:
16        high_score_file = open("high_score.txt", "r")
17        high_score = int(high_score_file.read())
18        high_score_file.close()
19        print("The high score is", high_score)
20    except IOError:
21        # Error reading file, no high score
22        print("There is no high score yet.")
23    except ValueError:
24        # There's a file there, but we don't understand the number.
25        print("I'm confused. Starting with no high score.")
27    return high_score
30def save_high_score(new_high_score):
31    try:
32        # Write the file to disk
33        high_score_file = open("high_score.txt", "w")
34        high_score_file.write(str(new_high_score))
35        high_score_file.close()
36    except IOError:
37        # Hm, can't write it.
38        print("Unable to save the high score.")
41def main():
42    """ Main program is here. """
43    # Get the high score
44    high_score = get_high_score()
46    # Get the score from the current game
47    current_score = 0
48    try:
49        # Ask the user for his/her score
50        current_score = int(input("What is your score? "))
51    except ValueError:
52        # Error, can't turn what they typed into a number
53        print("I don't understand what you typed.")
55    # See if we have a new high score
56    if current_score > high_score:
57        # We do! Save to disk
58        print("Yea! New high score!")
59        save_high_score(current_score)
60    else:
61        print("Better luck next time.")
63# Call the main function, start up the game
64if __name__ == "__main__":
65    main()

31.4. Exception Objects

More information about an error can be pulled from the exception object. This object can be retrieved while catching an error using the as keyword. For example:

Creating an exception
2    x = 5 / 0
3except ZeroDivisionError as e:
4    print(e)

The e variable points to more information about the exception that can be printed out. More can be done with exceptions objects, but unfortunately that is beyond the scope of this chapter. Check the Python documentation on-line for more information about the exception object.

31.5. Exception Generating

Exceptions may be generated with the raise command. For example:

Creating an exception
1# Generating exceptions
2def get_input():
3    user_input = input("Enter something: ")
4    if len(user_input) == 0:
5        raise IOError("User entered nothing")

Try taking the code above, and add exception handling for the IOError raised.

It is also possible to create custom exceptions, but that is also beyond the scope of this book. Curious readers may learn more by going to:


31.6. Proper Exception Use

Exceptions should not be used when if statements can just as easily handle the condition. Normal code should not raise exceptions when running the “happy path” scenario. Well-constructed try/catch code is easy to follow but code involving many exceptions and jumps in code to different handlers can be a nightmare to debug. (Once I was assigned the task of debugging code that read an XML document. It generated dozens of exceptions for each line of the file it read. It was incredibly slow and error-prone. That code should have never generated a single exception in the normal course of reading a file.)