try / except / else / finally
Run code that might fail, handle specific exceptions, and optionally run cleanup code whether it failed or not.
try:
...
except SpecificError:
...
else:
...
finally:
...
Purpose
A try block runs code that might raise an exception. except catches and handles specific
exception types; else runs only if the try block raised nothing at all; finally always runs,
whether an exception happened or not, whether it was caught or not.
Example
def parse_positive_int(raw: str) -> int:
try:
value = int(raw)
except ValueError:
raise ValueError(f"{raw!r} is not a valid integer") from None
else:
if value <= 0:
raise ValueError(f"{value} is not positive")
return value
Behavior notes
except SpecificError:catches only that type (and its subclasses) — code that isn’t part of thetryblock, and errors of a different type, both propagate normally.elseruns only when thetryblock completed without raising — it exists specifically so the “what to do if it worked” logic doesn’t accidentally sit inside thetryblock, where it would also be covered by theexceptclause if it happened to raise the same exception type. Above, the validity check runs only onceint(raw)has already succeeded.finallyalways runs — even if theexceptblock itself re-raises, even if areturnfires inside thetryorexceptblock. It’s the right place for cleanup that must happen regardless of outcome (closing a file, releasing a lock).raise NewError(...) from None(used above) suppresses Python’s default “during handling of the above exception, another exception occurred” chaining note — appropriate here because the originalValueErrorfromint()isn’t useful context for the caller; the new message already says everything they need.
Common mistakes
except:with no exception type (a “bare except”) catches everything, includingKeyboardInterruptand typos that raisedNameError— silently swallowing bugs that should have crashed loudly. Catch the specific exception type the code can actually recover from.- Putting code that shouldn’t be covered by
exceptinside thetryblock anyway — anything that can also raise the same exception type for an unrelated reason will be caught and misdiagnosed as the original failure. - Forgetting that
finallyruns even after areturninsidetry/except— areturninsidefinallyitself silently discards whatever thetry/exceptwas about to return, which is almost never intended.
Implementation notes
Exception-handling control flow — which clause runs when, and the guarantee that finally always
runs — is defined by the language itself, identical across conforming implementations.