Python Context Managers: Master the with Statement for Clean Resource Handling

Python Context Managers: Master the with Statement for Clean Resource Handling
6 views

Python context managers are the language’s answer to the question “how do I guarantee cleanup even when an exception occurs?” The with statement calls __enter__ on entry and __exit__ on exit — even if an exception is raised. This makes resource management both safe and readable.

⚡ TL;DR: with statement calls __enter__ on entry, __exit__ on exit (even on exception). Implement via __enter__/__exit__ methods or @contextmanager decorator. Use contextlib.suppress to ignore specific exceptions. ExitStack for dynamic context managers. Multiple managers in one with statement.

__enter__ and __exit__ — Python context managers

class DatabaseConnection:
  def __init__(self, dsn): self.dsn = dsn

  def __enter__(self):
    self.conn = create_connection(self.dsn)
    return self.conn  # Value bound to 'as' variable

  def __exit__(self, exc_type, exc_val, exc_tb):
    if exc_type:  # Exception occurred
      self.conn.rollback()
    else:
      self.conn.commit()
    self.conn.close()
    return False  # False = don't suppress exception
    # Return True to suppress the exception

with DatabaseConnection('postgresql://...') as conn:
  conn.execute('INSERT INTO ...')
  # Auto-commits or rolls back, always closes

@contextmanager — the easy way

from contextlib import contextmanager
import time

@contextmanager
def timer(name=''):
  start = time.perf_counter()
  try:
    yield  # Code inside 'with' block runs here
  finally:     # Runs even on exception
    elapsed = (time.perf_counter()-start)*1000
    print(f'{name}: {elapsed:.1f}ms')

with timer('database query'):
  results = db.execute('SELECT ...')  # Timed!

# Transaction context manager:
@contextmanager
def transaction(db):
  try:
    yield db
    db.commit()
  except:
    db.rollback()
    raise  # Re-raise after rollback

Multiple and nested managers

# Multiple managers in one with:
with open('input.txt') as f_in, open('output.txt','w') as f_out:
  f_out.write(f_in.read())
# Both files closed even if exception!

# contextlib.suppress — ignore specific exceptions:
from contextlib import suppress
with suppress(FileNotFoundError):
  os.remove('/tmp/temp_file')  # OK if file doesn't exist
# Same as: try/except FileNotFoundError: pass (but cleaner)

contextlib.ExitStack — dynamic managers

from contextlib import ExitStack

# Open variable number of files:
file_names = ['a.txt','b.txt','c.txt']
with ExitStack() as stack:
  files = [stack.enter_context(open(f)) for f in file_names]
  # All files open, all will be closed on exit
  data = [f.read() for f in files]

# ExitStack.callback: register any cleanup function
with ExitStack() as stack:
  conn = db.connect()
  stack.callback(conn.close)   # Always closes
  stack.callback(conn.rollback) # Always rolls back (if not committed)
  • ✅ @contextmanager for simple context managers (no class needed)
  • ✅ Multiple managers in one with statement
  • ✅ contextlib.suppress instead of empty except blocks
  • ✅ ExitStack for dynamic or variable numbers of managers
  • ❌ Never return True from __exit__ unless you intentionally suppress exceptions
  • ❌ Never put cleanup in finally when with handles it

External reference: Python contextlib documentation.

Recommended Reading

→ Designing Data-Intensive Applications — The bible of distributed systems and production engineering at scale.

→ The Pragmatic Programmer — Timeless engineering wisdom every senior developer needs.

Affiliate links. We earn a small commission at no extra cost to you.

Free Weekly Newsletter

🚀 Join 2,000+ Senior Developers

Get expert-level JavaScript, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.

✓ No spam✓ Unsubscribe anytime✓ Expert-level only

Related: Python Decorators Explained: From Simple Wrappers to Production Patterns · Python asyncio vs Threading vs Multiprocessing: When to Use Each · Python Dictionary Methods and Tricks: The Complete Guide

Related: Node.js Error Handling: From try/catch to Production Error Monitoring · Python Dictionary Methods and Tricks: The Complete Guide for 2025 · Day 64: Secret-Aware Context Filters

Deep-dive PDF

Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.

Already subscribed? or open the subscribe page.


Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a comment

No account needed. Name and email are optional.