What an exception is
When something goes wrong at runtime — a missing key, a bad conversion, a file that is not there — Python creates an exception object and raises it. Raising stops the current line and unwinds: out of the function, out of its caller, and so on up the stack, until some except catches it. If nothing does, the program prints the traceback and exits. That unwinding is the point: the error is handled at whatever level knows what to do about it, not where it happened.
def parse(text):return int(text)def load(rows):return [parse(r) for r in rows]try:load(["1", "2", "x"])except ValueError as e:print("bad row:", e)
Enter the try block and call load.
stack | [module] |
All 6 steps as a table
| Step | Line | What happened | Variables now |
|---|---|---|---|
| 1 | 8 | Enter the try block and call load. | stack = [module] |
| 2 | 5 | The comprehension calls parse("1") → 1, parse("2") → 2, then parse("x"). | stack = [module, load, parse] |
| 3 | 2 | int("x") cannot work. Python creates ValueError("invalid literal for int() with base 10: 'x'") and raises it. parse has no try, so its frame is abandoned. | stack = [module, load] |
| 4 | 5 | load has no try either. Its frame is abandoned too — the half-built list is discarded. | stack = [module] |
| 5 | 9 | Back in the module, the raise happened inside a try whose except ValueError matches. The exception is caught and bound to e. | |
| 6 | 10 | Handle it. Execution continues after the try/except as normal. |
You should see
bad row: invalid literal for int() with base 10: 'x'
type: ValueError
the program continues