Data Model
Context Managers
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>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>
handledNotes
- Files, locks, and temporary state commonly use context managers.
__enter__and__exit__power the protocol.- Use
finallywhen cleanup must happen after errors too. - Returning true from
__exit__suppresses an exception; do that only intentionally.
See also
- next depth: Exceptions
- related: Special Methods
- related: Descriptors
Run the complete example
Expected output
<section>
content
</section>
<error>
</error>
handled
Execution time appears here after you run the example.