Python Context Managers: Creating Custom with Blocks

Learn how to write custom context managers in Python. Master the contextmanager decorator and __enter__/__exit__ methods for resource safety.

Try Python Context Managers Code

Overview

Context managers are an elegant mechanism in Python designed to handle the setup and teardown of external resources. In software, many operations require pairs of actions: open and close files, connect and disconnect from databases, or acquire and release locks. If a program crashes after the setup step but before the teardown step, those resources remain locked in memory. Context managers guarantee that resources are cleaned up safely under all circumstances.

The standard way to invoke a context manager is using the `with` statement. Under the hood, any object used in a `with` statement must implement the Context Manager Protocol. This protocol consists of two special methods: `__enter__()` and `__exit__()`. When the `with` block begins, `__enter__()` is called to prepare the resource. When the `with` block finishes or raises an exception, `__exit__()` is automatically triggered, receiving information about any raised exception so it can handle cleanup or suppress errors.

For simple use cases, writing a class with `__enter__` and `__exit__` methods can feel verbose. To simplify this, Python's standard library provides the `contextlib` module, which features the `@contextmanager` decorator. This decorator allows you to write a simple generator function containing a single `yield` statement. The code before the `yield` acts as the setup, the yielded value acts as the resource, and the code after the `yield` represents the cleanup. Mastering context managers ensures your applications remain leak-free.

Code Example

A custom class implementing __enter__ and __exit__ to manage execution logging boundaries.

context_managers.py
Try in Editor
class CustomManager:
    def __enter__(self):
        print("--> Resource Setup: Entering the block")
        return "RESOURCE_KEY"

    def __exit__(self, exc_type, exc_value, traceback):
        print("<-- Resource Teardown: Exiting the block")
        if exc_type:
            print(f"Exception Intercepted: {exc_value}")
        return True  # Suppress exceptions

with CustomManager() as res:
    print(f"Working inside block with resource: {res}")
    # Force an error to verify exception handling
    x = 1 / 0
print("Program continues running safely.")
Terminal Output
--> Resource Setup: Entering the block
Working inside block with resource: RESOURCE_KEY
<-- Resource Teardown: Exiting the block
Exception Intercepted: division by zero
Program continues running safely.

Real-world Use Cases

  • Managing database transactions (commit on success, rollback on error)
  • Acquiring and releasing thread locks in multi-threaded code
  • Redirecting standard output (stdout) during unit testing scripts

Frequently Asked Questions

How do I suppress exceptions in a custom context manager?

By returning True from the __exit__ method. If it returns True, any exception raised inside the block will be suppressed.

Can you combine multiple context managers in one statement?

Yes, you can separate them with commas, e.g., with open('file1.txt') as f1, open('file2.txt') as f2:.

Keep Learning

Recommended Python Resources

Expand your knowledge with related interactive tutorials, cheat sheets, and code comparisons.