pvdocs /Python/With Statement

With Statement

The with statement guarantees that setup and teardown code runs reliably, even if an exception is raised. It is backed by the context manager protocol.

Basic Usage

with open("file.txt", "r") as f:
    content = f.read()
# f is automatically closed here — even if an exception occurred

How It Works Internally

with EXPR as VAR:
    BODY

# is equivalent to:
mgr = EXPR
VAR = mgr.__enter__()
try:
    BODY
except:
    if not mgr.__exit__(*sys.exc_info()):
        raise
else:
    mgr.__exit__(None, None, None)

Custom Context Manager (Class)

class Timer:
    def __enter__(self):
        import time
        self._start = time.perf_counter()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        elapsed = time.perf_counter() - self._start
        print(f"Elapsed: {elapsed:.4f}s")
        return False  # do not suppress exceptions

with Timer() as t:
    result = sum(range(1_000_000))

Custom Context Manager (Generator)

contextlib.contextmanager turns a generator into a context manager — much less boilerplate.

from contextlib import contextmanager

@contextmanager
def managed_resource(name):
    print(f"Acquiring {name}")
    try:
        yield name          # value bound to `as` variable
    finally:
        print(f"Releasing {name}")

with managed_resource("DB connection") as res:
    print(f"Using {res}")

Multiple Context Managers

# One with statement, multiple managers
with open("input.txt") as fin, open("output.txt", "w") as fout:
    fout.write(fin.read())

Common Use Cases

# Files
with open("data.txt") as f: ...

# Locks (thread safety)
import threading
lock = threading.Lock()
with lock:
    shared_state += 1

# Database transactions
with db.transaction():
    db.execute(...)

# Temporary directory
from tempfile import TemporaryDirectory
with TemporaryDirectory() as tmpdir:
    # tmpdir is deleted when the block exits
    ...

# Suppress specific exceptions
from contextlib import suppress
with suppress(FileNotFoundError):
    os.remove("maybe_exists.txt")

# Redirect stdout
from contextlib import redirect_stdout
import io
buf = io.StringIO()
with redirect_stdout(buf):
    print("captured")
output = buf.getvalue()

Key Interview Points