else and finally
Picture yourself mixing dough for a pie. If the dough turns out well, you put it in the oven. If it does not, you throw it away. And you wash the bowl in any case, whatever happens.
try has branches for exactly these three cases:
- the
exceptbranch is "it did not work"; - the
elsebranch is "it worked, let's go on"; - the
finallybranch is "wash the bowl in any case".
The else and finally branches go after all the except branches, at the same level as try:
def show_double(text):
try:
n = int(text)
except ValueError:
print("bad", end=" ")
else:
print(n * 2, end=" ")
finally:
print("checked")
show_double("5") # 10 checked
show_double("x") # bad checkedLet's see what happens on each call.
The call show_double("5"):
int("5")goes through, andnbecomes5.- The
exceptbranch is skipped, andelseprints10. - The
finallybranch printscheckedon the same line.
The call show_double("x"):
int("x")raises aValueError, and thetryblock breaks off.- The
exceptbranch printsbad, andelseis skipped. - The
finallybranch printscheckedagain.
The else branch
The else branch runs only if no exception happened in the try block. This word has already appeared with loops, but here it means something else: else on a try means "there was no error".
The same print(n * 2) could have stayed inside the try. But then except ValueError would also catch errors from that line, while only int(text) needs guarding. The else holds code whose errors this try must not catch.
Remember the rule: the try holds only the line that may fail in the expected way. Everything that goes on after its success moves to else.
The finally branch
The finally branch always runs. When exactly:
- after a successful
try; - after an
exceptthat ran; - even when nobody caught the exception—then Python runs
finallyfirst and prints the traceback after it.
That is why finally holds closing actions that must not be skipped. Here the bowl picture ends: in a kitchen you can forget to wash it, but Python never forgets the finally branch.
A try with a finally branch may have no except at all. If a function returns from try, except or else, finally still runs—before the value goes back to the caller:
def half(text):
try:
return int(text) // 2
finally:
print("half of", text, end=": ")
print(half("9")) # half of 9: 4Let's go step by step:
- The call
half("9")computes4on the line withreturn. - Before the function exits,
finallyruns and printshalf of 9:. - Only after that does the outer
printget4and print it on the same line.
The call half("x") would also print half of x: , but then the program would stop with a traceback: nobody caught the ValueError.
Interviewers like to ask: "Does finally run if the try has a return?" The answer is yes, it runs, and before the value goes back to the caller.
Common mistake
A return is written in finally:
def to_int(text):
try:
return int(text)
finally:
return 0 # ✗
print(to_int("7")) # 0
print(to_int("x")) # 0Python 3.12 reports no error. The return in finally replaces the value from try, so to_int("7") returns 0. It cancels the exception too: the ValueError from int("x") disappears with no traceback. Keep only closing actions in finally, and return the value from try, except or else.
Key points
- The
elsebranch runs only if thetryraised no exception; it holds code whose errors thetrymust not catch. - The
finallybranch always runs: after success, afterexcept, and before the traceback of an uncaught exception. - On a
returnfromtry, thefinallybranch runs before the value goes back to the caller. - A
returninfinallyreplaces the value and cancels the exception, sofinallyholds only closing actions.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.