with statements & contextlib.contextmanager

Clean up with context managers

Lesson 14 of 20 · 12 min · Module 4: When things go wrong

Some actions must always be undone: closing a file, releasing a lock, restoring a setting. A with block guarantees the cleanup runs, even when an error happens inside.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Use with blocks for guaranteed cleanup
  • Write a context manager with contextmanager
  • Distinguish "missing" from None

The idea

@contextmanager from contextlib turns a generator into a context manager: code before yield runs when the block starts, and code in a finally after it runs when the block ends, whether it ended normally or with an exception.

from contextlib import contextmanager

@contextmanager
def announce(name):
    print("start", name)
    try:
        yield
    finally:
        print("end", name)

with announce("backup"):
    print("working")

01with guarantees cleanup

with open("data.txt") as f closes the file even if your code crashes halfway. Context managers bring the same safety to any setup-and-teardown pair.

02yield splits setup and cleanup

Code before yield is the setup. The body of the with block runs at the yield. finally runs afterwards in every case, including exceptions.

from contextlib import contextmanager

@contextmanager
def step(name):
    print("begin", name)
    try:
        yield
    finally:
        print("done", name)

with step("deploy"):
    print("…")
Output
begin deploy
…
done deploy

03Sentinels

mapping.get(key) returns None for a missing key and for a stored None. A private object() is equal only to itself, so it reliably marks "there was no value".

Your turn

Write a context manager temporary_value(mapping, key, value). Inside the with block, mapping[key] equals value. Afterwards, the old value is restored, or the key is removed if it did not exist before. This must also happen when the block raises an exception, and the exception must not be swallowed.

What the checks look for

  • Sets the value inside the block and restores it after
  • Removes a key that did not exist before
  • Restores even when the block raises, and does not swallow the error
  • Keeps a stored None value
Try it in the editor →

Take this with you

Context managers pair setup with guaranteed cleanup.

Go a little further

Write a context manager timer() that measures how long the with block took using time.perf_counter().

Learn Python Intermediate for free

20 short lessons with real code and instant checks.

See the whole course →