Mastery
Mastery/Python/G. Error handling
T1 · high-leverage
Compare with Java: What happens to an in-flight exception during cleanup

try/except/else/finally -- what else is actually for

else runs only if the try block completed with no exception -- its entire purpose is separating "code that might raise" (in try) from "code that should only run if it didn't" (in else), so the except block's own errors aren't accidentally caught by a broader net. finally always runs, no exceptions -- and that "always" is stronger than most people expect: a return inside finally overrides a return from try, and can even silently swallow an in-flight exception.

python
def demo(should_raise):
    try:
        if should_raise:
            raise ValueError("boom")
        print("  try succeeded")
    except ValueError:
        print("  except ran")
    else:
        print("  else ran (only because try succeeded, not part of the except's error handling)")
    finally:
        print("  finally always runs")

demo(False)
demo(True)

The genuinely dangerous part: return in finally wins over everything, INCLUDING an exception that was actively propagating:

python
def finally_overrides_return():
    try:
        return "from try"
    finally:
        return "from finally"   # this wins -- the try's return value is silently discarded

print("finally overriding return:", finally_overrides_return())

def finally_swallows_exception():
    try:
        raise ValueError("this exception vanishes")
    finally:
        return "finally's return value"   # the ValueError never propagates -- swallowed with no trace

print("finally swallowing an exception entirely:", finally_swallows_exception())

Interview angle

"What does else do in a try/except that finally doesn't?" is a great small question because most Python developers have never used try's else clause at all — it's one of the least-used pieces of core syntax, and knowing it exists (and why it's more correct than just appending code after the except block) is a real signal of having read the language reference rather than pattern-matched from Stack Overflow.

In the industry

The finally-overrides-return gotcha is a real, documented trap — linters (pylint's lost-exception, ruff's equivalent) specifically flag a return/break/continue inside a finally block, because it's almost never intentional and it silently discards whatever exception or return value was in flight. Any code reviewer who's been burned by it once treats a bare return inside finally as an automatic red flag for the rest of their career.