Wiki
Core12 min read

Exceptions: a control path, not a crash

try/except/else/finally routes errors to handlers, and finally is the one block that always runs.

Every non-trivial operation can fail: opening a missing file, parsing text that is not a number, dividing by zero. Language designers before exceptions handled this by returning error codes and hoping every caller checked. Python instead lets an operation raise an exception and unwinds the call stack until a handler catches it — or the program stops with a traceback.

Errors travel upward until caught

A raise is a jump out of the current function and into the nearest enclosing handler for that exception type. If there is none, the interpreter prints the traceback and exits. This is why a function can be written for the happy path and still not lose information when something fails.

The stepper runs a real try block over different inputs, so each press shows which handler catches the error and whether the else and finally blocks run.

Change the input and step through which handler catches the error

1try:
2 n = int(text)
3 y = 10 / n
4except ValueError:
5 y = None
6except ZeroDivisionError:
7 y = -1
8else:
9 note = "ok"
10finally:
11 closed = True
n
—
y
—
finally
pending

enter the try block

1 / 8

Exactly one except clause runs, and Python checks them top to bottom; else runs only when nothing was raised. The finally block is the one guaranteed stop — it runs on every path, including a bare return inside try, which is why cleanup code lives there.

The five clauses

  • try marks the guarded block.
  • except SomeError catches that type (and its subclasses), in top-to-bottom order. The first match wins.
  • else runs only if the try block raised nothing.
  • finally always runs, on success, on failure, and even on a return inside try. This is where cleanup belongs.
  • raise signals an exception deliberately.
try:
    n = int(text)
    y = 10 / n
except ValueError:
    y = None                 # text was not a number
except ZeroDivisionError:
    y = -1                   # n was zero
else:
    note = "ok"              # only when nothing was raised
finally:
    closed = True            # always

Catch the specific, not everything

An except Exception: that swallows every error will hide the bug you need to see. Name the types you can actually handle and let the rest propagate. Catching too much is indistinguishable from ignoring failures.

Order matters: subclasses before superclasses

FileNotFoundError is a subclass of OSError. If you write except OSError: before except FileNotFoundError:, the specific clause can never run. Python picks the first matching clause, so list the most specific types first.

Raising and defining errors

Use raise to refuse an operation that cannot be completed correctly:

def withdraw(balance, amount):
    if amount > balance:
        raise ValueError("insufficient funds")
    return balance - amount

For a project's own failure modes, define a small exception class that inherits from a built-in such as ValueError. Callers can then catch your specific type without catching unrelated errors of the same base.

Cleanup with context managers

Because finally is easy to forget, Python offers the with statement for resources that must be released:

with open("notes.txt") as f:
    text = f.read()

The file is closed when the block exits, even on an exception. Prefer with over a hand-written try/finally for files, locks and connections.

Illustrative vs real

The stepper models only three outcomes on a fixed micro-program. Real tracebacks carry a traceback object with the exact file and line of each frame, raise ... from ... keeps the cause, and exception groups handle several failures at once. The routing rule — first matching handler, finally always runs — is exactly what the panel computes.

Check yourself

Eduspheria wiki · Programming & Data Structures, Objects and I/O

0 / 5 answered

  1. 1Which clause always runs, whether or not an exception occurred?
    Multiple choice
  2. 2The else clause of a try statement runs when an exception was raised.
    True / false
  3. 3Which statement deliberately signals an error from inside a function?
    Short answer
  4. 4Why must `except FileNotFoundError` come before `except OSError`?
    Multiple choice
  5. 5How many of the clauses try, except, else and finally are guaranteed to execute at most once per try statement?
    Numeric answer

From the exam paper

Modeled on NITJ AI-503, End-Sem December 2024

0 / 4 answered

  1. 1A square-root function must refuse a negative input. Which built-in exception type is the natural one to raise for an invalid value?
    Short answer
  2. 2The function returns the square root of a non-negative input. What value does it return for the input 144?
    Numeric answer
  3. 3The function raises ValueError when its input is negative. At the call site, which clause catches that error and lets the program continue?
    Multiple choice
  4. 4If a function raises an exception and no handler is present anywhere up the call stack, the program stops and prints a traceback.
    True / false

Where next: files and modules — where a program's data lives and how it is organised into importable pieces.