stackademic

The leading education platform for anyone with an interest in software development.

Python Context Managers

Guarantee setup and teardown with the with statement and contextlib

Overview

Context managers define what happens when entering and leaving a with block—typically acquiring and releasing resources. Files, locks, and database connections commonly use this pattern to prevent leaks even when errors occur.

Syntax / Usage

# Built-in: files
with open("data.txt") as f:
    data = f.read()
# file automatically closed

# Multiple managers
with open("in.txt") as src, open("out.txt", "w") as dst:
    dst.write(src.read())

# Custom context manager (class)
class Timer:
    def __enter__(self):
        import time
        self.start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc, tb):
        import time
        print(f"Elapsed: {time.perf_counter() - self.start:.4f}s")
        return False  # do not suppress exceptions

with Timer():
    sum(range(1_000_000))

# contextlib decorator
from contextlib import contextmanager

@contextmanager
def temporary_env(key, value):
    import os
    old = os.environ.get(key)
    os.environ[key] = value
    try:
        yield
    finally:
        if old is None:
            del os.environ[key]
        else:
            os.environ[key] = old

Examples

Database transaction pattern (conceptual):

@contextmanager
def transaction(conn):
    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise

Suppress errors for optional cleanup:

from contextlib import suppress

with suppress(FileNotFoundError):
    Path("temp.cache").unlink()

Common Mistakes

  • Returning True from __exit__ and silently swallowing exceptions
  • Not using context managers for locks, sockets, or DB connections
  • Implementing __enter__ without matching cleanup in __exit__

See Also

python-exceptions python-file-io python-decorators