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
try
andexcept
are used for error handling in Python.Write code that catches and handles specific error types.
Use
else
to execute code when no error occurs.Use
finally
to 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:
Exception
is the base class for most common error types in Python (such asValueError
,TypeError
,ZeroDivisionError
, etc.).as e
assigns the actual error object to the variablee
.You can then use
e
to 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:
else
runs if no error occurs in thetry
block.finally
runs 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
except
block runs.If the input is valid, the
else
block runs.The
finally
block 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
except
andelse
.
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
try
andexcept
to 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/except
block 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 aValueError
if the user types something that is not a number.By placing this line inside a
try/except
block, we can catch the error and respond gracefully.The
except ValueError
block 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#
try
andexcept
prevent your programme from crashing.Always prefer catching specific error types.
Use
else
for code that should only run if no error occurs.Use
finally
for code that should always run.