Site Tools


python-context-managers

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):

  • @contextlib.contextmanager decorator on generator function
  • Yield the resource; code after yield runs on exit
  • Cleaner than writing a class with __enter__ and __exit__

Return value from __enter__:

  • Often return self to access the resource
  • Can return a different object
  • Assigned to the variable after as in with statement

__exit__ parameters:

  • exc_type: exception class (None if no exception)
  • exc_val: exception instance
  • exc_tb: exception traceback
  • Return True to suppress the exception; False to re-raise

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:

  • Multiple with statements can nest: with A() as a, B() as b:
  • Or traditional nesting: with A() as a: with B() as b:
  • Resources acquired in order; cleaned up in reverse

Common uses:

  • File handling (with open(...))
  • Locks and mutexes (with lock:)
  • Database transactions (with db.transaction():)
  • Temporary directory changes (with chdir(...))
  • Timing/profiling (with timer():)
  • Mocking and patching (with patch(...):)
python-context-managers.md · Last modified: by 127.0.0.1