Fundamentals 8 min read

Understanding Python's with Statement and Context Managers with Practical Examples

This article explains Python's with statement as a context management tool, describes the required __enter__ and __exit__ methods, and provides multiple practical examples—including file handling, custom managers, multiple managers, third‑party resources, and automation scenarios—to illustrate reliable resource acquisition and cleanup.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Understanding Python's with Statement and Context Managers with Practical Examples

In Python, the with statement is a context management tool used to ensure that resources are properly acquired and released, even when exceptions occur, making it ideal for tasks such as file handling, locking, and network connections.

To use with , a class must implement the context manager protocol by defining __enter__() and __exit__() methods. __enter__() prepares the resource and optionally returns an object for the as clause, while __exit__() handles cleanup and receives exception information.

Example 1: File operation

with open('example.txt', 'r') as file:
    content = file.read()
    print(content)

Example 2: Custom context manager

class ManagedResource:
    def __enter__(self):
        print("Initializing resource...")
        # initialize resource
        return self  # return manager or other object
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resource...")
        # clean up resource
        if exc_type is not None:
            print(f"An exception of type {exc_type} occurred.")
        return False  # do not suppress exceptions

with ManagedResource() as resource:
    print("Using resource...")
    raise ValueError("An error occurred!")

Example 3: Multiple context managers

with open('file1.txt', 'w') as file1, open('file2.txt', 'w') as file2:
    file1.write("Hello, world!\n")
    file2.write("Goodbye, world!")

Example 4: Using a third‑party library (threading.Lock)

import threading
lock = threading.Lock()
with lock:
    # critical section code
    print("Critical section executed.")

Example 5: Simplifying with contextlib

import contextlib
@contextlib.contextmanager
def managed_resource():
    print("Initializing resource...")
    try:
        yield "resource"  # return resource
    finally:
        print("Cleaning up resource...")

with managed_resource() as res:
    print(f"Using resource: {res}")

Advanced examples for API automation

Using with to manage a requests session ensures the session is closed after use.

import requests

def test_session_with_auth():
    url = "https://api.example.com/data"
    headers = {"Authorization": "Bearer your_token"}
    with requests.Session() as session:
        session.headers.update(headers)
        response = session.get(url)
    assert response.status_code == 200
    assert "data" in response.json()

Managing temporary files with with guarantees they are closed and can be deleted.

import tempfile, json, os

def test_upload_file():
    data = {"key": "value"}
    with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
        tmp.write(json.dumps(data))
        filename = tmp.name
    url = "https://api.example.com/upload"
    files = {'file': open(filename, 'rb')}
    with requests.post(url, files=files) as response:
        assert response.status_code == 200
    os.remove(filename)

Using with for a SQLite connection ensures the database is properly closed.

import sqlite3

def test_database_query():
    db_file = 'test.db'
    query = 'SELECT * FROM users WHERE id = ?'
    with sqlite3.connect(db_file) as conn:
        cursor = conn.cursor()
        cursor.execute(query, (1,))
        result = cursor.fetchall()
    assert len(result) == 1

Managing environment variables within a with block (illustrative example) restores the original state after the block.

import os

def test_environment_variable():
    original_value = os.getenv('TEST_VAR')
    with os.environ['TEST_VAR'] = 'test_value':
        assert os.getenv('TEST_VAR') == 'test_value'
    assert os.getenv('TEST_VAR') == original_value

Using a lock in multithreaded tests with with guarantees the lock is released.

import threading

def test_thread_lock():
    lock = threading.Lock()
    shared_data = []
    def worker():
        with lock:
            shared_data.append(threading.current_thread().ident)
    threads = [threading.Thread(target=worker) for _ in range(5)]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    assert len(shared_data) == 5

Summary

These examples demonstrate how the with statement can be employed in API automation testing and general Python programming to manage sessions, files, database connections, environment variables, and locks, ensuring proper initialization and cleanup of resources for more reliable and efficient code.

Pythonautomationtestingresource managementContext Managerwith-statement
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.