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 and except 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

Hide code cell output

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[1], line 4
      2 x = 5
      3 y = 0
----> 4 result = x / y  # ZeroDivisionError

ZeroDivisionError: division by zero

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!")

Hide code cell output

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!")

Hide code cell output

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.")

Hide code cell output

Error: division by zero.

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 as ValueError, TypeError, ZeroDivisionError, etc.).

  • as e assigns the actual error object to the variable e.

  • 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 the try 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 and else.


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 and except 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.


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.



Key Points#

  • try and except 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.