Predict the output · Python
Exceptions and finally
Which blocks run, in which order, and what is returned.
Learn: try, except, else and finally: what Python runs7 minute read
An exception is an error object that Python raises (starts) when something goes wrong, such as int("x"). A try statement in Python has up to four parts: try, except, else and finally. Output questions check that you know exactly when each part runs and what a function returns. Testers use these parts in real code, for example to quit a browser in finally or to retry a call that sometimes fails, so the rules matter beyond the interview.
Rule 1: an exception skips the rest of the try block
When a line raises, the remaining lines of the try block do not run. Python checks the except clauses from top to bottom and runs the first one that matches the exception's class or a parent class. (For example, KeyError is a kind of LookupError, so a clause for LookupError also catches it.) Only one clause runs. Unlike Java, Python does not complain when a broad clause comes before a narrow one: the narrow clause simply never runs. A tuple such as except (KeyError, IndexError) matches any of its types.
Rule 2: else runs only when nothing was raised
The else block runs after the try block finishes without an exception. It is skipped when any exception happened, even a handled one, and also when the try block leaves early through return, break or continue. Code in else is not protected by the except clauses above it, which is the reason to put it there: its own errors are not caught by mistake.
Rule 3: finally always runs
finally runs on every way out: normal end, handled or unhandled exception, return, break or continue. With an unhandled exception it runs first, and then the error continues upward to the caller. If it reaches the top of the script, Python prints the traceback (the list of calls that led to the error) to standard error, a separate place for error messages, and stops; lines already printed to standard output, the normal printed text, stay.
def load(value):
try:
number = int(value)
except ValueError:
return "bad"
else:
return number * 2
finally:
print("checked", value)
print(load("4"))
print(load("x"))
checked 4 8 checked x bad
checked 4 prints before 8 because the outer print needs the return value first, and finally runs before the function returns.
Rule 4: return values and finally
When return x runs, the object x refers to is saved, then finally runs. Assigning a new object to x in finally (rebinding) changes nothing for the caller, but mutating the saved object (for example appending to a list) is visible. A return inside finally replaces the pending return value and silently discards a pending exception. Avoid it.
Rule 5: the name after as is deleted
In except ValueError as e, the name e exists only inside that block. Python deletes it when the block ends, so using e afterwards raises NameError, the error for a name that does not exist. Copy what you need, such as str(e), into another variable.
def f():
try:
raise KeyError("id")
except LookupError as e:
print("caught", repr(e))
return "from except"
finally:
print("cleanup")
print(f())
caught KeyError('id')
cleanup
from except
Rule 6: with statements exit in reverse order
A context manager is an object used in a with statement, such as an open file. Python calls __enter__ (the method that runs when the block starts) on each one in the order written and __exit__ (the method that runs when it ends) in reverse order, even when the body raises. __exit__ receives the exception. If it returns a true value the exception is swallowed; otherwise it continues to any surrounding except.
How errors print
print(e) shows the message passed to the exception. For a KeyError the message is the key's repr, so it shows quotes. repr(e) shows the class name and arguments.
How to answer in an interview
Trace the path through the flowchart: which line raises, which clause matches, whether else runs, then finally. Say each step out loud. If asked when to use else, answer directly: for code that should run only when the try part worked, kept out of try so its errors are not swallowed.
Common mistakes
- Running
elseafter a handled exception. - Expecting the narrow
exceptto win when a broad one comes first. - Printing the return value before the
finallyoutput. - Using the
as ename after the block. - Exiting context managers in the order they were entered.
Recap
A raise skips the rest of try, and the first matching except runs. else runs only with no exception, and finally runs on every path. The return value is saved before finally, but a return in finally overrides it. The as name is deleted after the block, and with exits in reverse order.
11 questions0/11 solved
| Status | Question | Difficulty | Asked in |
|---|---|---|---|
| Not started | try, except, else and finally when an error happens | Easy | |
| Not started | One function, a good input and a bad input | Easy-Medium | |
| Pro+ | return inside try with a finally block | Easy-Medium | |
| Pro+ | return in both try and finally | Medium | |
| Pro+ | Which except block catches a KeyError? | Medium | |
| Pro+ | An exception travelling up through finally | Medium | |
| Pro+ | finally with an exception nobody catches | Medium | |
| Pro+ | finally changes the variable after return | Medium-Hard | |
| Pro+ | finally inside a loop with continue and break | Medium-Hard | |
| Pro+ | Two context managers and an error in the body | Medium-Hard | |
| Pro+ | Using the exception name after the except block | Hard |
The first 2 questions of each topic are free. Pro+ opens every question.