Data Model

Context Managers

with ensures setup and cleanup happen together.

A class-based context manager implements __enter__ and __exit__. The value returned by __enter__ is bound by as when the with statement uses it.

Source

class Tag:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print(f"<{self.name}>")
        return self

    def __exit__(self, exc_type, exc, tb):
        print(f"</{self.name}>")
        return False

with Tag("section"):
    print("content")

Output

<section>
content
</section>
inbodyout
A context manager pairs setup with reliable cleanup; the raise path still routes through __exit__.

contextlib.contextmanager writes the same setup/cleanup shape as a generator. Code before yield is setup, and code after yield is cleanup.

Source

from contextlib import contextmanager

@contextmanager
def tag(name):
    print(f"<{name}>")
    try:
        yield
    finally:
        print(f"</{name}>")

with tag("note"):
    print("body")

Output

<note>
body
</note>

Cleanup still runs when the block raises. Returning False from __exit__, or letting a generator context manager re-raise, allows the exception to keep propagating.

Source

try:
    with tag("error"):
        raise ValueError("boom")
except ValueError:
    print("handled")

Output

<error>
</error>
handled

Notes

See also

Run the complete example

Example code

Expected output

<section>
content
</section>
<error>
</error>
handled

Execution time appears here after you run the example.