Error Handling
A track of P31 · Typing & Robust Code.
Error handling as deliberate design: EAFP over LBYL, exception hierarchies you can catch at the right level, chaining that preserves the original cause, and preconditions that reject bad input at the door.
The most common error-handling code in the world is except: pass, and it is
also the worst: it swallows every failure — including the KeyboardInterrupt you
meant to let through — and destroys the evidence. Good error handling is the
opposite of that reflex. It is designed, with the same care as the type
system, and this track teaches the design.
You build an exception hierarchy — a domain base class with specific
subclasses — so a caller can catch broadly (except OrderError) or narrowly
(except OutOfStock), whichever it needs. You practise EAFP, Python's
"try it and handle the exception" style, over the check-first LBYL that invites a
time-of-check/time-of-use race. You chain errors with raise DomainError(...) from exc, translating a low-level failure into a meaningful one without losing
the original cause in the traceback. And you enforce preconditions at the
boundary with guard clauses that raise, so the rest of a function can trust its
inputs — reserving assert for the internal invariants that -O is allowed to
strip.
The through-line is a single decision, asked at every layer: raise or return?
Raise for a broken precondition or a genuinely exceptional condition; return a
value or None for an expected "not found" that is part of normal flow. Errors
are control flow you design, not accidents you paper over.