The try/except keywords

So far, we have reviewed and tested all our examples assuming the ideal condition, that is, the execution of the program will encounter no errors. On the contrary, applications fail from time to time either due to external factors, such as invalid user input and poor Internet connectivity, or program logic errors caused by the programmer. In such cases, we want the program to report/log the nature of error and either continue its execution or clean up resources before exiting the program. The try/except keywords offer a mechanism to trap an error that occurs during a program's execution and take remedial action. Because it is possible to trap and log an error in crucial parts of the code, the try/except keywords are especially useful while debugging an application.

Let's understand the try/except keywords by comparing two examples. Let's build a simple guessing game where the user is asked to guess a number between 0 and 9:

  1. A random number (between 0 and 9) is generated using Python's random module. If the user's guess of the generated number is right, the Python program declares the user as the winner and exits the game.
  2. If the user input is the letter x, the program quits the game.
  3. The user input is converted into an integer using the int() function. A sanity check is performed to determine whether the user input is a number between 0 and 9.
  4. The integer is compared against a random number. If they are the same, the user is declared the winner and the program exits the game.

Let's observe what happens when we deliberately provide an erroneous input to this program (the code snippet shown here is available for download along with this chapter as guessing_game.py):

import random

if __name__ == "__main__":
while True:
# generate a random number between 0 and 9
rand_num = random.randrange(0,10)

# prompt the user for a number
value = input("Enter a number between 0 and 9: ")

if value == 'x':
print("Thanks for playing! Bye!")
break

input_value = int(value)

if input_value < 0 or input_value > 9:
print("Input invalid. Enter a number between 0 and 9.")


if input_value == rand_num:
print("Your guess is correct! You win!")
break
else:
print("Nope! The random value was %s" % rand_num)

Let's execute the preceding code snippet and provide the input hello to the program:

    Enter a number between 0 and 9: hello
Traceback (most recent call last):
File "guessing_game.py", line 12, in <module>
input_value = int(value)
ValueError: invalid literal for int() with base 10: 'hello'

In the preceding example, the program fails when it is trying to convert the user input hello to an integer. The program execution ends with an exception. An exception highlights the line where the error has occurred. In this case, it has occurred in line 10:

    File "guessing_game.py", line 12, in <module>
input_value = int(value)

The nature of the error is also highlighted in the exception. In this example, the last line indicates that the exception thrown is ValueError:

    ValueError: invalid literal for int() with base 10: 'hello'

Let's discuss the same example (available for download along with this chapter as try_and_except.py) that makes use of the try/except keywords. It is possible to continue playing the game after trapping this exception and printing it to the screen. We have the following code:

import random

if __name__ == "__main__":
while True:
# generate a random number between 0 and 9
rand_num = random.randrange(0,10)

# prompt the user for a number
value = input("Enter a number between 0 and 9: ")

if value == 'x':
print("Thanks for playing! Bye!")

try:
input_value = int(value)
except ValueError as error:
print("The value is invalid %s" % error)
continue

if input_value < 0 or input_value > 9:
print("Input invalid. Enter a number between 0 and 9.")
continue

if input_value == rand_num:
print("Your guess is correct! You win!")
break
else:
print("Nope! The random value was %s" % rand_num)

Let's discuss how the same example works with the try/except keywords:

  1. From the previous example, we know that when a user provides the wrong input (for example, a letter instead of a number between 0 and 9), the exception occurs at line 10 (where the user input is converted into an integer), and the nature of the error is named ValueError.
  2. It is possible to avoid interruption of the program's execution by wrapping this in a try...except block:
      try: 
input_value = int(value)
except ValueError as error:
print("The value is invalid %s" % error)
  1. On receiving a user input, the program attempts converting the user input into an integer under the try block.
  2. If ValueError has occurred, error is trapped by the except block, and the following message is printed to the screen along with the actual error message:
       except ValueError as error:
print("The value is invalid %s" % error)
  1. Try executing the code example and try providing an invalid input. You will note that the program prints the error message (along with the nature of the error) and goes back to the top of the game loop and continues seeking valid user input:
       Enter a number between 0 and 9: 3
Nope! The random value was 5
Enter a number between 0 and 9: hello
The value is invalid invalid literal for int() with
base 10: 'hello'

Enter a number between 0 and 10: 4
Nope! The random value was 6

The try...except block comes with a substantial processing power cost. Hence, it is important to keep the try...except block as short as possible. Because we know that the error occurs on the line where we attempt converting the user input into an integer, we wrap it in a try...except block to trap an error.

Thus, the try/except keywords are used to prevent any abnormal behavior in a program's execution due to an error. It enables logging the error and taking remedial action. Similar to the try...except block, there are also try...except...else and try...except...else code blocks. Let's quickly review those options with a couple of examples.