Python Context Managers — Resources Done Right

Python AdvancedContext ManagersFree Lesson

Advertisement

Python Context Managers — Resources Done Right

Context managers ensure proper acquisition and release of resources. The with statement guarantees cleanup even if errors occur.

Learning Objectives

  • Understand the with statement protocol
  • Create context managers with classes and contextlib
  • Use nested and async context managers
  • Apply context managers for locks, transactions, and cleanup

The with Statement

# Without context manager — error-prone
f = open('file.txt', 'r')
try:
    data = f.read()
finally:
    f.close()

# With context manager — safe and clean
with open('file.txt', 'r') as f:
    data = f.read()
# File is automatically closed

Class-Based Context Manager

class ManagedResource:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print(f"Acquiring {self.name}")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Releasing {self.name}")
        if exc_type is not None:
            print(f"Error occurred: {exc_val}")
        return False  # Don't suppress exceptions

with ManagedResource("database") as resource:
    print(f"Using {resource.name}")
# Acquiring database
# Using database
# Releasing database

contextlib Decorator

from contextlib import contextmanager

@contextmanager
def managed_file(filename, mode):
    try:
        f = open(filename, mode)
        yield f
    finally:
        f.close()

with managed_file('test.txt', 'w') as f:
    f.write("Hello, World!")

Common Patterns

from contextlib import contextmanager, suppress, redirect_stdout
import io, time

# Timing context manager
@contextmanager
def timer():
    start = time.perf_counter()
    yield
    elapsed = time.perf_counter() - start
    print(f"Elapsed: {elapsed:.4f}s")

with timer():
    sum(range(1000000))

# Suppress specific exceptions
with suppress(FileNotFoundError):
    os.remove('nonexistent.txt')

# Redirect stdout
f = io.StringIO()
with redirect_stdout(f):
    print("captured output")
captured = f.getvalue()

Exit Stack — Dynamic Context Managers

from contextlib import ExitStack

def process_files(filenames):
    with ExitStack() as stack:
        files = [stack.enter_context(open(fn)) for fn in filenames]
        for f in files:
            print(f.read()[:100])

Key Takeaways

  1. Use with for any resource that needs cleanup
  2. __enter__ acquires, __exit__ releases
  3. contextlib.contextmanager simplifies creation
  4. ExitStack handles dynamic numbers of context managers
  5. Context managers guarantee cleanup even on exceptions

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement