Lesson 7 of 34 · 0 of 3 exercises solved

Error Handling

Programs run into problems: missing files, bad input, failed network . try/except lets you handle those instead of letting the program crash.

Python uses try/except blocks for exception handling. You can catch specific exception types, multiple types, or all exceptions. Always be as specific as possible — catching all exceptions hides .

# Basic try/except
try:
    result = 10 / 0
except ZeroDivisionError:
    print("You can't divide by zero!")

# Multiple exception types
try:
    num = int("not a number")
except ValueError as e:
    print(f"Value error: {e}")
except TypeError as e:
    print(f"Type error: {e}")

# else — runs if no exception occurred
try:
    result = 10 / 2
except ZeroDivisionError:
    print("Division error")
else:
    print(f"Result: {result}")   # Result: 5.0

# finally — always runs
try:
    f = open("data.txt", "r")
    content = f.read()
except FileNotFoundError:
    print("File not found")
finally:
    print("This always runs")    # cleanup code goes here

# Raising exceptions
def divide(a, b):
    if b == 0:
        raise ValueError("Denominator cannot be zero")
    return a / b

try:
    divide(10, 0)
except ValueError as e:
    print(e)   # Denominator cannot be zero
Python (loads on first run)Ctrl+Enter runs

For file and resource handling, Python's is the idiomatic approach. It automatically closes the file even if an exception occurs — no finally needed.

# Context managers — the right way to handle files
with open("data.txt", "r") as f:
    content = f.read()
# file is automatically closed here

# Writing to a file
with open("output.txt", "w") as f:
    f.write("Hello, file!\n")
    f.write("Second line\n")

# Reading line by line (memory-efficient for large files)
with open("data.txt", "r") as f:
    for line in f:
        print(line.strip())   # strip() removes the trailing newline

# Custom exceptions
class InsufficientFundsError(Exception):
    def __init__(self, amount, balance):
        self.amount = amount
        self.balance = balance
        super().__init__(f"Cannot withdraw {amount}. Balance: {balance}")

def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFundsError(amount, balance)
    return balance - amount
Python (loads on first run)Ctrl+Enter runs

Common question

Should I check for problems first, or just try it and handle the error?

An exception is an object that travels up the until something catches it. It has a type, which says what kind of thing went wrong, and a message, which says how. Python raises them for the many things that can fail (missing keys, bad conversions, missing files), and you can raise your own when a cannot do what it promised.

The habit is: try the operation, catch exactly what you can handle, and leave everything else alone. Use else for code that should run only if nothing was raised, and finally for cleanup that must always run. Use the with statement for resources so cleanup is automatic. Define your own exception classes when callers need to tell your failures apart from Python's.

Source: The Zen of Python: "Errors should never pass silently. Unless explicitly silenced."

Common mix-ups

Each of these sounds reasonable. Think about why it is wrong, then open the explanation.

  • Exceptions are for rare situations, so ordinary cases like a missing file should be checked with if first.

  • A bare except is safest because it catches everything.

  • Raising exceptions is rude, because it forces the caller to deal with the failure.

Practice

Write safe_divide(a, b) that returns a / b, but returns instead of crashing when b is zero.

Exercise

Catch the crash

3 checks
def safe_divide(a, b):
    return a / b


print(safe_divide(10, 2))
print(safe_divide(1, 0))
 
Python (loads on first run)Ctrl+Enter runs
Output
Press Run to try your code, then Check answer to grade it.

Write to_ints() that converts a of strings to integers, silently skipping any that are not valid numbers. ["1", "x", "3"] should give [1, 3].

Exercise

Skip the bad ones

3 checks
def to_ints(strings):
    result = []
    for s in strings:
        result.append(int(s))
    return result


print(to_ints(["1", "x", "3", "4.5", "10"]))
 
Python (loads on first run)Ctrl+Enter runs
Output
Press Run to try your code, then Check answer to grade it.

Define a custom exception InsufficientFunds and a function withdraw(balance, amount) that returns the new balance, or raises InsufficientFunds with a helpful message when the amount exceeds the balance.

Exercise

Raise your own exception

4 checks
class InsufficientFunds(Exception):
    pass


def withdraw(balance, amount):
    ...


print(withdraw(100, 30))
try:
    withdraw(100, 500)
except InsufficientFunds as e:
    print("Refused:", e)
 
Python (loads on first run)Ctrl+Enter runs
Output
Press Run to try your code, then Check answer to grade it.

Check yourself

Quick check

When does the finally block run?

Finished reading?3 exercises still open. You can come back to them later.

Tip: use the ← and → keys to move between lessons.