Useful Data Tips

Context Managers and the 'with' Statement

⏱️ 28 sec read 🐍 Python

Context managers handle resource setup and cleanup automatically using the 'with' statement. They ensure proper resource management even when errors occur.

File Handling: The Classic Example

# Without context manager (bad - file may not close)
f = open('file.txt', 'r')
data = f.read()
f.close()  # Might not execute if error occurs

# With context manager (good - file always closes)
with open('file.txt', 'r') as f:
    data = f.read()
# File automatically closed here, even if exception occurs

Database Connections

import sqlite3

# Connection automatically commits and closes
with sqlite3.connect('database.db') as conn:
    cursor = conn.cursor()
    cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
    # Automatically commits if no error
    # Automatically rolls back if error occurs
# Connection closed here

Multiple Context Managers

# Python 3.1+: Multiple resources
with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
    for line in infile:
        outfile.write(line.upper())
# Both files closed automatically

Creating Your Own Context Manager

Using a Class

class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self

    def __exit__(self, *args):
        self.end = time.time()
        print(f"Elapsed: {self.end - self.start:.2f} seconds")

with Timer():
    # Code to time
    sum([i**2 for i in range(1000000)])
# Prints: Elapsed: 0.15 seconds

Using @contextmanager Decorator

from contextlib import contextmanager

@contextmanager
def temporary_setting(name, value):
    # Setup
    import os
    old_value = os.environ.get(name)
    os.environ[name] = value

    try:
        yield  # Code block runs here
    finally:
        # Cleanup
        if old_value is None:
            del os.environ[name]
        else:
            os.environ[name] = old_value

with temporary_setting('DEBUG', 'true'):
    print(os.environ['DEBUG'])  # 'true'
# DEBUG setting restored to original value

Practical Use Cases

# Temporarily change directory
from contextlib import contextmanager
import os

@contextmanager
def working_directory(path):
    old_dir = os.getcwd()
    os.chdir(path)
    try:
        yield
    finally:
        os.chdir(old_dir)

with working_directory('/tmp'):
    # Work in /tmp
    pass
# Back to original directory

When to Use Context Managers

Pro Tip: Always use 'with' for files and database connections. It guarantees cleanup even during exceptions. Use @contextmanager for simple cases; use __enter__ and __exit__ for complex resource management.

← Back to Python Tips