Context Managers Checkpoint
25 min · Intermediate
Need help? Ask a tutor on WhatsApp (opens in a new tab)Fix the mistakes
The slips that cost marks in this module. Spot each one, then check the fix.
A real export job opens files, changes a setting for a moment and must clean up after any failure. This checkpoint builds that job from context managers and tests the whole module.
Pick the simplest manager
Use a built-in manager when one exists, such as open or a lock. Use @contextmanager for short single-use setup and cleanup. Use a class when you need attributes, reuse or fine control of errors.
from contextlib import contextmanager
@contextmanagerdef export_mode(settings): settings["exporting"] = True try: yield settings finally: settings["exporting"] = FalseExample 1 · Export mode with rollback on error
from contextlib import contextmanager
settings = {"exporting": False}rows = []
@contextmanagerdef export_mode(): settings["exporting"] = True saved = list(rows) try: yield rows except Exception: rows[:] = saved raise finally: settings["exporting"] = False
with export_mode() as r: r.append("order 1")print(rows, settings["exporting"])
try: with export_mode() as r: r.append("order 2") raise RuntimeError("write failed")except RuntimeError: print(rows, settings["exporting"])['order 1'] False ['order 1'] False
What this code does
finallyalways switches the setting off;exceptrolls the rows back and re-raises.- The caller still sees the
RuntimeError.
The setting is turned on for the block and always switched off, even after a failure.
Nest managers and read the order
Managers enter from left to right and exit from right to left. The first resource opened is the last one closed, so later ones can safely rely on earlier ones.
with section("outer"): with section("inner"): print("body")Example 2 · Order of nested managers
from contextlib import contextmanager
@contextmanagerdef section(name): print("enter", name) try: yield finally: print("exit", name)
with section("outer"), section("inner"): print("body")enter outer enter inner body exit inner exit outer
What this code does
- Two managers in one
withline behave like nested blocks. - The cleanup order is the reverse of the setup order.
The order is: enter outer, enter inner, body, exit inner, exit outer.
Decide about errors
Let errors continue by default. Suppress only a named, expected error with suppress(...), and keep its block small. A manager that rolls back should still re-raise.
with suppress(FileNotFoundError): os.remove("old-report.csv")Example 3 · A class manager with state
class Counter: opened = 0
def __enter__(self): Counter.opened += 1 return self
def __exit__(self, exc_type, exc, tb): return exc_type is KeyError
with Counter(): {}["x"]print("still running", Counter.opened)try: with Counter(): 1 / 0except ZeroDivisionError: print("passed through", Counter.opened)still running 1 passed through 2
What this code does
- The
KeyErroris suppressed because the check returnsTrue. - A
ZeroDivisionErrorreturnsFalse, so it continues to the caller.
If the file is missing, the program carries on. Any other error still stops the program.
Finish up
Mark complete & continue
Next: Annotating Functions and Classes