Table of Contents

Python context managers

Python context managers are objects that define __enter__ and __exit__ to manage setup and teardown around a with block. They guarantee cleanup runs even if an exception occurs, making them ideal for resource management (files, locks, database connections).

Context managers eliminate try/finally boilerplate and make resource handling declarative and clear.

Example

This example implements a context manager for database connections and timing.

# run: python3 context_managers.py
# description: custom context manager for resource management
 
import time
 
class DatabaseConnection:
    def __init__(self, name):
        self.name = name
        self.connected = False
 
    def __enter__(self):
        print(f"Connecting to {self.name}...")
        time.sleep(0.1)  # simulate connection time
        self.connected = True
        return self
 
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Disconnecting from {self.name}...")
        self.connected = False
 
        if exc_type is not None:
            print(f"Exception occurred: {exc_type.__name__}: {exc_val}")
        return False  # don't suppress exception
 
    def query(self, sql):
        if not self.connected:
            raise RuntimeError("Not connected")
        return f"Result of: {sql}"
 
# Use context manager
with DatabaseConnection("MyDB") as db:
    print(db.query("SELECT * FROM users"))
 
print("Connection closed after with block\n")
 
# Exception handling
try:
    with DatabaseConnection("MyDB") as db:
        print(db.query("SELECT * FROM users"))
        raise ValueError("Bad query")
except ValueError:
    print("Caught exception (cleanup still ran)")

Common patterns

Decorator approach (simpler for simple cases):

Return value from __enter__:

__exit__ parameters:

Generator version:

from contextlib import contextmanager
 
@contextmanager
def database(name):
    print(f"Connecting to {name}...")
    try:
        yield None  # resource goes here
    finally:
        print(f"Disconnecting from {name}...")

Nested contexts:

Common uses: