PyPython · Lesson 7 of 14

Error Handling

Things go wrong. Files don't exist. Users type letters when you expected numbers. APIs return 500. Python's try/except lets you handle these gracefully instead of crashing.

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 bugs.

Python
# 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

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

Python
# 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