CodeNebula
Python🔧Core Languagebeginner

Context Managers and `with`

Python · Core Language · Run with python3

Explanation

The `with` statement guarantees cleanup code runs even if exceptions occur. Any object implementing `__enter__` / `__exit__` is a context manager. The `contextlib.contextmanager` decorator lets you write generator-based context managers — `yield` is the body of the `with` block. `contextlib.ExitStack` composes a dynamic number of context managers.

Real-World Scenario

Database transactions: `with db.transaction():` commits on success, rolls back on any exception — no `try/finally` boilerplate needed. Opening multiple files simultaneously: `with open(a) as f1, open(b) as f2:` ensures both are closed even if the second `open` raises. ```python import contextlib import time @contextlib.contextmanager def timed(label: str): start = time.perf_counter() try: yield finally: elapsed = time.perf_counter() - start print(f"{label}: {elapsed:.4f}s") @contextlib.contextmanager def managed_resource(name: str): print(f"Acquiring {name}") try: yield name.upper() finally: print(f"Releasing {name}") with timed("demo"): with managed_resource("database") as res: print(f"Using {res}") ```

Quick Snippet

snippet.py
import contextlib
import time

@contextlib.contextmanager
def timed(label: str):
    start = time.perf_counter()
    try:
        yield
    finally:
        elapsed = time.perf_counter() - start
        print(f"{label}: {elapsed:.4f}s")

@contextlib.contextmanager
def managed_resource(name: str):
    print(f"Acquiring {name}")
    try:
        yield name.upper()
    finally:
        print(f"Releasing {name}")

with timed("demo"):
    with managed_resource("database") as res:
        print(f"Using {res}")

Full Example

context_managers.py
# Compile: python3 context_managers.py
# Output:
# Acquiring database
# Using DATABASE
# Releasing database

import contextlib
import time

@contextlib.contextmanager
def timed(label: str):
    start = time.perf_counter()
    try:
        yield
    finally:
        elapsed = time.perf_counter() - start
        print(f"{label}: {elapsed:.4f}s")

@contextlib.contextmanager
def managed_resource(name: str):
    print(f"Acquiring {name}")
    try:
        yield name.upper()
    finally:
        print(f"Releasing {name}")

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

# __enter__ / __exit__ directly
class TempDirectory:
    def __enter__(self):
        import tempfile, os
        self.path = tempfile.mkdtemp()
        return self.path

    def __exit__(self, exc_type, exc_val, exc_tb):
        import shutil
        shutil.rmtree(self.path, ignore_errors=True)
        return False  # Don't suppress exceptions

with TempDirectory() as tmpdir:
    print(f"Temp dir: {tmpdir}")
print("Temp dir cleaned up")
Run command
python3 context_managers.py