← Back to Python Course | Chapter 11: Advanced Python | Lesson 4 of 12

Python Context Managers

A context manager sets something up and cleans it up for you, like a helper who opens a door and closes it behind you. The with statement uses it so nothing is left open.
Syntax
python
with expression as variable:
    # use resource; cleanup is automatic

class ContextClass:
    def __enter__(self):
        return resource
    def __exit__(self, exc_type, exc_value, traceback):
        # cleanup

The with Statement

A context manager guarantees that setup and teardown code around a block runs reliably -- the with statement is what lets Python call that setup before the block and the teardown after it, even if the code inside the block raises an exception partway through.

Example: The with Statement

python
with open("data.txt", "w") as f:
    f.write("hello")
print("File automatically closed after the block")  # teardown ran even without an explicit close()

Class-Based Context Managers

Writing your own context manager as a class means implementing __enter__ (runs when the with block starts, often returning a resource to use) and __exit__ (runs when the block ends, responsible for releasing that resource) -- this is the traditional, explicit way to build one.

Example: Class-Based Context Managers

python
class Resource:
    def __enter__(self):  # runs when the with block starts
        print("Acquiring resource")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):  # runs when the with block ends
        print("Releasing resource")

with Resource():
    print("Using resource")

Generator-Based Context Managers

The @contextmanager decorator from contextlib lets you write a context manager as a single generator function instead of a full class -- code before the yield acts as __enter__, the yielded value is what 'as x' captures, and code after the yield acts as __exit__.

Example: Generator-Based Context Managers

python
from contextlib import contextmanager

@contextmanager
def resource():
    print("Acquiring")  # code before yield acts like __enter__
    yield "resource"  # this value is what "as r" captures
    print("Releasing")  # code after yield acts like __exit__

with resource() as r:
    print("Using", r)

Handling Exceptions inside context

__exit__ receives the exception type, value, and traceback as arguments if the with block raised one -- returning True from __exit__ tells Python the exception was handled and should be suppressed, while returning False (or nothing) lets it propagate normally after cleanup runs.

Example: Handling Exceptions inside context

python
class Suppressor:
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Suppressing:", exc_val)
        return True  # tells Python the exception was handled

with Suppressor():
    raise ValueError("boom")  # caught and suppressed by __exit__
print("Execution continues")

Practical Uses of Context Managers

Context managers are the standard tool for anything that needs guaranteed cleanup regardless of success or failure -- file handles, network sockets, database connections, and locks are all commonly wrapped this way so resources are never accidentally left open.

Example: Practical Uses of Context Managers

python
with open("data.txt", "w") as f:
    f.write("saved")
with open("data.txt") as f:
    print(f.read())  # file is guaranteed to be closed after each block
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Writing __enter__ without returning the object, so with ... as x gives x = None.
  2. Forgetting the three parameters of __exit__, as in def __exit__(self):, which raises TypeError when the block ends.
  3. Returning True from __exit__ by accident, which silently swallows exceptions raised inside the block.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.