How do context managers and the with statement work in Python?

· Category: Python Programming

Short answer

A context manager ensures that setup and teardown code runs around a block, even if exceptions occur. The with statement is the standard way to use them. Implement __enter__ and __exit__ in a class, or use contextlib.contextmanager with a generator.

Steps

  1. Define __enter__ to return the resource.
  2. Define __exit__ to clean up, accepting exception info.
  3. Use with MyContext() as resource:.
class ManagedFile:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with ManagedFile("test.txt", "w") as f:
    f.write("Hello")

Tips

  • contextlib.contextmanager is a simpler way to write context managers using yield.
  • contextlib.closing ensures .close() is called on objects that have it but are not context managers.
  • Multiple context managers can be nested in a single with line.
from contextlib import contextmanager

@contextmanager
def managed_list():
    data = []
    try:
        yield data
    finally:
        print(f"Final list length: {len(data)}")

with managed_list() as lst:
    lst.append(1)
    lst.append(2)

Common issues

  • If __enter__ raises an exception, __exit__ is not called.
  • __exit__ receives exception info; returning True suppresses the exception, which is usually undesirable unless intended.
  • Forgetting to yield exactly once in a contextmanager generator breaks the protocol.