Back to Python

Python Context Managers

Introduction to Context Managers

Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement.

# Traditional file handling without context manager
file = open('example.txt', 'r')
try:
    content = file.read()
finally:
    file.close()

# Using context manager (recommended)
with open('example.txt', 'r') as file:
    content = file.read()
# File is automatically closed after the block

Context managers ensure that resources are properly managed, even if an exception occurs within the block. They follow the protocol of __enter__ and __exit__ methods.

Creating Context Managers

You can create your own context managers using either class-based approach or the contextlib module.

# Class-based context manager
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

# Using the custom context manager
with FileManager('example.txt', 'w') as f:
    f.write('Hello, context manager!')

# Using contextlib for simpler context managers
from contextlib import contextmanager

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

with file_manager('example.txt', 'r') as f:
    content = f.read()

The contextmanager decorator from contextlib lets you write context managers using generator functions, which is often more concise than writing a class.

Common Use Cases

Context managers are useful for many resource management scenarios beyond just file handling.

# Database connections
with psycopg2.connect(database_uri) as conn:
    with conn.cursor() as cursor:
        cursor.execute("SELECT * FROM users")
        results = cursor.fetchall()

# Locks for threading
import threading
lock = threading.Lock()

with lock:
    # Critical section - thread-safe code here
    shared_resource += 1

# Temporary changes
import os
from contextlib import chdir

with chdir('/path/to/directory'):
    # Current directory is changed here
    print(os.getcwd())
# Directory is automatically restored

Context managers help ensure proper cleanup in all these scenarios, making your code more robust and less prone to resource leaks.

Advanced Context Managers

Python's contextlib module provides several utilities for working with context managers.

# Handling multiple context managers
from contextlib import ExitStack

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # All files will be closed when the block exits

# Ignoring exceptions
from contextlib import suppress

with suppress(FileNotFoundError):
    os.remove('somefile.tmp')
# If file doesn't exist, the error is suppressed

# Redirecting stdout
from contextlib import redirect_stdout
import io

f = io.StringIO()
with redirect_stdout(f):
    print('This goes to the StringIO')
print('This goes to stdout')
print(f.getvalue()) # Shows the captured output

These advanced techniques allow you to handle complex resource management scenarios with clean, readable code.

Python Context Managers Videos

Master Python context managers with these handpicked YouTube tutorials:

Context Manager Basics

Learn the fundamentals of context managers:

Creating Context Managers

How to implement your own context managers:

Advanced Techniques

Powerful context manager patterns:

Practical Applications

Real-world uses of context managers:

Python Context Managers Quiz