Python Context Managers
In this page:
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
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
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
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
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
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
- Writing
__enter__without returning the object, sowith ... as xgivesx = None. - Forgetting the three parameters of
__exit__, as indef __exit__(self):, which raisesTypeErrorwhen the block ends. - Returning
Truefrom__exit__by accident, which silently swallows exceptions raised inside the block.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first: