Error Handling#
Learning Objectives
Questions:
What happens when errors occur in a programme?
How can error handling improve the user experience?
Why is it important to handle different errors in different ways?
Objectives:
Understand how
tryandexceptare used for error handling in Python.Write code that catches and handles specific error types.
Use
elseto execute code when no error occurs.Use
finallyto execute code that must always run.
try and except#
Errors are common in programming. Instead of letting your programme stop when an error occurs, you can use try and except to handle the problem gracefully.
This makes your programme more robust and provides clearer feedback to the user.
Basic structure#
The simplest use of error handling is to place code that might fail inside a try block. If an error occurs, the code in the except block is executed.
try:
# code that might cause an error
except:
# code that runs if an error occurs
This allows you to separate the “normal” behaviour of your code from the way you want to handle problems.
However, a completely bare except: is not recommended, because it catches too much. This will be explained in more detail under A general catch-all.
Example: Division by zero#
If you attempt to divide by zero, Python raises a ZeroDivisionError and immediately stops the programme:
# without try/except the programme stops
x = 5
y = 0
result = x / y # ZeroDivisionError
With try and except, the programme can handle the problem gracefully:
# with try/except the error is handled
x = 5
y = 0
try:
result = x / y
print("Result:", result)
except:
print("You cannot divide by zero!")
The second version prevents the crash and provides a useful message for the user.
Catching specific error types#
It is best practice to catch specific error types. If you only write except: without specifying the error, you might hide problems that you did not expect. By naming the error type, you make your code more precise.
try:
number = int("abc") # ValueError
except ValueError:
print("Only numbers are allowed!")
In this example, the programme handles the ValueError that occurs when trying to convert non-numeric text into an integer.
Multiple except blocks#
Sometimes different kinds of errors can occur in the same block of code. In that case, you can write more than one except block. Python will run the first one that matches the error.
try:
x = 5 / 0
except ZeroDivisionError:
print("Error: division by zero.")
except ValueError:
print("Error: invalid number.")
This way, each error is handled in the most appropriate way.
A general catch-all#
Even if you handle specific errors, your programme might still encounter something unexpected.
In such cases, it can be useful to add a general catch-all at the end.
The recommended form is except Exception as e:, which captures all “ordinary” errors that inherit from the Exception class.
try:
number = int(input("Enter a number: "))
result = 10 / number
except ValueError:
print("You must enter a valid number.")
except ZeroDivisionError:
print("You cannot divide by zero.")
except Exception as e:
print("An unexpected error occurred:", e)
This approach allows you to log or display unforeseen errors without crashing the programme.
It still lets system-level events such as KeyboardInterrupt (Ctrl+C) and SystemExit work normally, because they do not inherit from Exception.
The syntax except Exception as e: means:
Exceptionis the base class for most common error types in Python (such asValueError,TypeError,ZeroDivisionError, etc.).as eassigns the actual error object to the variablee.You can then use
eto display or log information about what went wrong.
except Exception as e:
print("An unexpected error occurred:", e)
In this example, if an unforeseen error happens, the error message will be printed together with the text.
For instance, if the error was trying to open a file that does not exist, the output would be:
An unexpected error occurred: [Errno 2] No such file or directory: 'missing.txt'
Why not use a bare except:?#
A completely bare except: will catch everything, including KeyboardInterrupt and SystemExit.
That means you could block the user from stopping the programme or interfere with Python shutting down.
For this reason, it is considered bad practice and should be avoided.
Good vs bad practice#
# Good: catch specific errors, and optionally a general catch-all
try:
number = int(input("Enter a number: "))
except ValueError:
print("Not a valid number.")
except Exception as e:
print("Unexpected error:", e)
# Bad: a bare except hides everything, even system-level errors
try:
number = int(input("Enter a number: "))
except:
print("Something went wrong.") # too vague and dangerous
Using else and finally#
Python also allows two optional blocks:
elseruns if no error occurs in thetryblock.finallyruns always, whether there was an error or not.
The purpose of else is to separate code that is risky (in the try) from code that should only run if everything went well.
You could place that code inside the try block, but then it would be skipped as soon as an error occurred. By putting it in else, you make it clear which part is error-prone and which part is normal flow.
try:
number = int(input("Enter a number: "))
except ValueError:
print("Not a valid number.")
else:
# only runs if no error
print("You entered:", number)
finally:
print("Programme finished.")
In this example:
If the input is not a number, the
exceptblock runs.If the input is valid, the
elseblock runs.The
finallyblock always runs, regardless of what happened.
Exercises#
Exercise 1: Handling numbers#
Write a programme that asks the user for a number.
If the user types something that is not a number, catch the error and display a message.
Extend the programme to use both
exceptandelse.
Solution
user_input = input("Enter a number: ")
try:
number = int(user_input)
except ValueError:
print("That was not a number!")
else:
print("Thank you, you entered the number:", number)
Exercise 2: IndexError with a fruit list#
Write a programme that asks the user to select an item from a list of fruits.
The list should contain at least three fruit names.
Ask the user to enter a number (index) to choose a fruit.
Use
tryandexceptto handle the following cases:The user types something that is not a number (
ValueError).The user enters a number that is outside the valid range (
IndexError).
If the input is valid, print the selected fruit.
Solution
fruits = ["apple", "banana", "cherry"]
try:
index = int(input("Enter a number (0-2) to choose a fruit: "))
choice = fruits[index]
except ValueError:
print("You must enter a valid number.")
except IndexError:
print("That number is out of range. Please try 0, 1, or 2.")
else:
print("You chose:", choice)
Exercise 3: Fixing The number guessing game#
In this exercise, you will update the solution the number guessing game so that it can handle invalid input.
import random
# Generate a random secret number between 1 and 20
secret_number = random.randint(1, 20)
# Keep track of the number of attempts
attempts = 0
# Initialise the variable to store the user's guess
user_guess = None
print("Welcome to the Number Guessing Game!")
# Continue looping until the correct number is guessed
while user_guess != secret_number:
# Ask the user to guess the secret number
user_guess = int(input("Guess the secret number (1-20): "))
# Increase the attempts counter
attempts = attempts + 1
# Compare the guess with the secret number
if user_guess == secret_number:
print("Congratulations! You guessed the correct number in", attempts, "attempts.")
elif user_guess < secret_number:
print("Too low. Try again.")
else:
print("Too high. Try again.")
At the moment, if the user types something that is not a whole number (integer), the program will crash.
Your task is to place the code that asks for a guess inside a try/except block. If the input is not an integer, the program should print a helpful message and allow the user to try again.
Requirements
Use a
try/exceptblock around the line where the program converts input to an integer.If the user does not type a valid number, print an error message such as:
"Invalid input. Please enter a number."Make sure the game continues running until the secret number is guessed.
Solution
import random
# Generate a random secret number between 1 and 20
secret_number = random.randint(1, 20)
# Keep track of the number of attempts
attempts = 0
# Initialise the variable to store the user's guess
user_guess = None
print("Welcome to the Number Guessing Game!")
# Continue looping until the correct number is guessed
while user_guess != secret_number:
try:
# Ask the user to guess the secret number
user_guess = int(input("Guess the secret number (1-20): "))
# Increase the attempts counter
attempts = attempts + 1
# Compare the guess with the secret number
if user_guess == secret_number:
print("Congratulations! You guessed the correct number in", attempts, "attempts.")
elif user_guess < secret_number:
print("Too low. Try again.")
else:
print("Too high. Try again.")
except ValueError:
# Handle invalid input
print("Invalid input. Please enter a number.")
Explanation
The line
user_guess = int(input(...))can raise aValueErrorif the user types something that is not a number.By placing this line inside a
try/exceptblock, we can catch the error and respond gracefully.The
except ValueErrorblock prints a helpful message and the program continues without crashing.
This way, the game only accepts valid integers, but still lets the user try again if they make a mistake.
An even cleaner solution would be to use a try/except/else structure.
In this way, the try block only contains the code that might fail, the except block handles the error, and the else block contains the normal program logic.
This separation can make the code easier to read and maintain.
import random
# Generate a random secret number between 1 and 20
secret_number = random.randint(1, 20)
# Keep track of the number of attempts
attempts = 0
# Initialise the variable to store the user's guess
user_guess = None
print("Welcome to the Number Guessing Game!")
# Continue looping until the correct number is guessed
while user_guess != secret_number:
try:
# Ask the user to guess the secret number
user_guess = int(input("Guess the secret number (1-20): "))
except ValueError:
# Handle invalid input
print("Invalid input. Please enter a number.")
else:
# Increase the attempts counter
attempts = attempts + 1
# Compare the guess with the secret number
if user_guess == secret_number:
print("Congratulations! You guessed the correct number in", attempts, "attempts.")
elif user_guess < secret_number:
print("Too low. Try again.")
else:
print("Too high. Try again.")
Key Points#
tryandexceptprevent your programme from crashing.Always prefer catching specific error types.
Use
elsefor code that should only run if no error occurs.Use
finallyfor code that should always run.