← Back to Chapters

Python Context Managers

? Python Context Managers

⚡ Quick Overview

A context manager in Python is used to safely manage resources like files, network sockets, or database connections. The most common way to use a context manager is with the with statement, which ensures that resources are cleaned up automatically, even if an error occurs inside the block.

Context managers help you write cleaner, safer code by handling common setup/teardown patterns for you.

? Key Concepts

  • Context manager: An object that defines what to do when entering and exiting a block of code.
  • with statement: Used to wrap the execution of a block with a context manager.
  • __enter__ and __exit__: Special methods that define the behavior of a custom context manager class.
  • contextlib.contextmanager: A decorator that makes it easier to create context managers using a simple function and yield.
  • Automatic cleanup: Ensures resources are released (like closing files) without needing manual calls.

? Syntax and Theory

The basic syntax of the with statement is:

? General with Syntax
with expression as variable:
    # use the resource
    ... # do something inside context

Under the hood, this works roughly like:

  • expression must return an object implementing __enter__ and __exit__.
  • __enter__() is called and its result is assigned to variable.
  • The block inside with is executed.
  • When done, __exit__() is always called.

? Code Examples

? Using with with Files

The most common use of context managers is file handling.

? View File Handling Example
with open("example.txt", "w") as file:
    file.write("Hello, World!")  # write to file

# File is automatically closed after the block

?️ Creating a Custom Context Manager with a Class

You can define your own context managers using a class.

? View Custom Class Example
class MyContext:
    def __enter__(self):
        print("Entering the block")  # before block
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting the block")  # after block

with MyContext() as ctx:
    print("Inside the block")  # inside

? Using contextlib for Simpler Context Managers

The contextlib module lets you use generators for context managers.

? View contextlib Example
from contextlib import contextmanager

@contextmanager
def my_context():
    print("Entering")  # before block
    yield # control passes to caller
    print("Exiting")  # after block

with my_context():
    print("Inside")  # inside

? Live Output and Explanation

?️ What These Examples Do

  • File example: Creates a file and writes text.
  • MyContext class: Prints messages before/after block.
  • contextlib example: Prints entering/inside/exiting.

If an exception occurs inside a with block, __exit__ (or post-yield code) still runs.

?️ When to Use Context Managers

  • Managing file I/O
  • Network connections
  • Locks in multithreaded programs
  • Database connections
  • Any setup → use → cleanup pattern

? Tips & Best Practices

  • Use with for resources that must be released.
  • Create custom context managers to simplify repeated patterns.
  • Use contextmanager decorator for simple cases.
  • Keep cleanup logic simple and focused.
  • Return helpful values from __enter__.

? Try It Yourself

  • Create a timing context manager.
  • Write a DB connection manager.
  • Log block start/end using contextlib.
  • Modify __exit__ to suppress errors.