PYTHON

Python Context Manager: Syntax, Usage, and Examples

A Python context manager handles the setup and cleanup of resources in your programs. It helps manage files, database connections, threads, locks, and other resources that require clean opening and closing. With a context manager, you don’t need to write repetitive error-handling or closing code. Python takes care of that for you using the with statement.

Using a context manager ensures your resources are released even if the code inside the block raises an error. This makes your code more robust and readable.


Why Use a Python Context Manager

Resource management is a common requirement in programming. For example, if you open a file or database connection, you must close it when done. Forgetting to do that can lead to memory leaks, locked files, or corrupted data.

Instead of manually writing try-finally blocks to handle cleanup, you can use a context manager Python offers through the with statement. The code becomes easier to read and less error-prone.


The Basics of Context Manager Python Implementation

A Python context manager uses two special methods behind the scenes:

  • __enter__(): Runs when the with block starts.
  • __exit__(exc_type, exc_value, traceback): Runs when the block exits, regardless of whether an exception occurred.

Here’s a simple custom context manager implemented using a class:

class SimpleContext:
    def __enter__(self):
        print("Entering context")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting context")

with SimpleContext():
    print("Inside the block")

This code prints:

Entering context
Inside the block
Exiting context

You can define any logic inside these methods to manage resources like files, connections, or locks.


The Python With Context Manager Pattern

The most familiar use of a context manager is with file handling:

with open("example.txt", "r") as file:
    data = file.read()

This example uses a Python with context manager approach to open a file. Python guarantees the file is closed once the block finishes, even if reading fails.

This method prevents common mistakes like leaving a file open or forgetting to release system resources.


Create a Context Manager Python Class

If you want to manage a custom resource, define a class that implements __enter__() and __exit__().

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

    def __exit__(self, exc_type, exc_value, traceback):
        from time import time
        self.end = time()
        print(f"Elapsed: {self.end - self.start:.2f} seconds")

with Timer():
    sum([i for i in range(1000000)])

The code calculates how long the block takes to run and prints the elapsed time. This is a great use case for performance testing.


Create a Context Manager Python Function with contextlib

You don’t always need a full class to build a context manager. The contextlib module provides a decorator called @contextmanager that lets you create one using a generator.

from contextlib import contextmanager

@contextmanager
def managed_file(name):
    f = open(name, "w")
    try:
        yield f
    finally:
        f.close()

with managed_file("output.txt") as f:
    f.write("Hello, context manager")

This version requires less code and works well for simpler use cases.

To create a context manager Python developers prefer for small tasks, using contextlib is usually the best approach.


Combine Multiple Context Managers in One Line

Python allows combining several context managers in a single line:

with open("input.txt") as infile, open("output.txt", "w") as outfile:
    outfile.write(infile.read())

This is cleaner than nesting with blocks and ensures all resources are properly handled.


Exception Handling Inside Context Managers

Sometimes you want the context manager to handle exceptions. In your __exit__() method, if you return True, Python suppresses the exception. This is helpful when you want to log or gracefully handle an error.

class SafeExecutor:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print(f"Handled error: {exc_value}")
            return True  # suppresses the exception

with SafeExecutor():
    raise ValueError("Something went wrong")

print("Continues running")

Use this technique when you want controlled behavior on failure, but don’t suppress exceptions blindly.


Real Use Case: Managing Database Connections

Let’s say you want to manage a database session. You can use a context manager to make sure the session is closed even if something goes wrong.

class DatabaseSession:
    def __enter__(self):
        self.connection = connect_to_database()
        return self.connection

    def __exit__(self, exc_type, exc_value, traceback):
        self.connection.close()

with DatabaseSession() as db:
    db.execute("SELECT * FROM users")

This is an efficient and safe way to use database resources.


Common Built-In Context Managers

Python includes several useful built-in context managers beyond file operations. These include:

  • threading.Lock(): Manages concurrency locks
  • decimal.localcontext(): Controls precision in decimal operations
  • contextlib.suppress(): Ignores specific exceptions

Example using suppress:

from contextlib import suppress

with suppress(FileNotFoundError):
    open("missing.txt")

This prevents the program from crashing if the file doesn’t exist.


Nesting Context Managers

You can nest context managers if you want more control over resource management order:

from contextlib import contextmanager

@contextmanager
def outer():
    print("Entering outer")
    yield
    print("Exiting outer")

@contextmanager
def inner():
    print("Entering inner")
    yield
    print("Exiting inner")

with outer():
    with inner():
        print("Inside inner context")

This prints:

Entering outer
Entering inner
Inside inner context
Exiting inner
Exiting outer

Each context manager enters and exits in the expected sequence.


What Happens If You Forget exit()

If your context manager doesn’t include __exit__, Python won’t know how to clean up your resource. That can cause memory leaks, unclosed files, or locks that never release. Always include both __enter__ and __exit__ methods or use the @contextmanager decorator to avoid mistakes.


Best Practices for Context Managers

  • Use context managers to reduce repetitive code and increase safety.
  • Always implement __exit__() if using a custom class.
  • Prefer contextlib.contextmanager for simple one-off tasks.
  • Don’t use them to silently suppress exceptions unless you have a clear reason.
  • Combine them when you need multiple resources to be managed simultaneously.

The Python context manager makes code cleaner, safer, and more reliable by automatically handling resource allocation and cleanup. You’ve seen how to use built-in managers like open() and how to build your own using classes or decorators. You also explored use cases involving files, timing, exception suppression, and database sessions.

Learn to Code in Python for Free
Start learning now
button icon
To advance beyond this tutorial and learn Python by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH

Reach your coding goals faster