What do the else and finally clauses of a try block do, and when does finally NOT run?
The else clause runs only when the try block exits without raising an exception — it lets you separate success-path code from the guarded block. The finally clause runs in every case: after normal exit, after an exception (caught or uncaught), and after a return or break inside try or except. The only situations where finally is skipped are a hard interpreter crash (SIGKILL, os._exit, power loss).
How to think about it
What the question is really after
Most candidates know try/except. The follow-up on else and finally tests whether you understand the execution model precisely — especially the subtle ways finally interacts with return and break. Getting this right signals you write production-grade code, not just happy-path code.
Full anatomy of a try block
The four clauses have distinct roles:
try:
result = risky_call() # guarded code
except ValueError as e:
handle_value_error(e) # specific exception
except (TypeError, KeyError) as e:
handle_other(e) # multiple types
else:
process(result) # ONLY if try succeeded
finally:
cleanup() # ALWAYS runs
The else clause is the subtle one. Without it you’d be tempted to put process(result) inside the try block — but then any exception process raises would be caught by the except handlers, which is almost never what you want. else separates “protected code” from “success-path code” cleanly.
Try it yourself
finally survives break and continue
for i in range(3):
try:
if i == 1:
break
finally:
print(f"cleanup {i}") # runs for i=0 and i=1 (the break)
When finally genuinely does not run
os._exit()— bypasses the Python interpreter shutdown entirely.SIGKILLsent from outside the process — the OS terminates without unwinding the stack.- A C-level segfault in an extension — the interpreter crashes before Python’s exception machinery runs.
import os
try:
os._exit(1) # no finally, no atexit handlers
finally:
print("never printed")
The key insight
Think of else as “then” and finally as “always”. The pattern try / except / else / finally maps directly to: “try this, handle errors, do this on success, always clean up.” Keeping those four concerns in separate clauses makes control flow transparent in code review.