__enter__ and __exit__ Protocol
Build context managers using the dunder protocol.
__enter__ and __exit__ Protocol is a free Python Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Context Manager Protocol
Any object that defines __enter__ and __exit__ is a context manager and can be used with with.
class Managed:
def __enter__(self):
print("entering")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exiting")
return False
with Managed() as m:
print("inside")__enter__ Return Value
__enter__ is called at the start of the with block. Its return value is bound to the variable after as.
class Resource:
def __enter__(self):
self.value = 42
return self # bound to 'r'
def __exit__(self, *args):
self.value = None
return False
with Resource() as r:
print(r.value) # 42__exit__ Arguments
__exit__(exc_type, exc_val, exc_tb) receives exception info if an error occurred. If no exception, all three are None.
class Safe:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is ValueError:
print(f"Suppressed ValueError: {exc_val}")
return True # suppress the exception
return False # re-raise anything else
with Safe():
raise ValueError("oops") # suppressedSuppressing Exceptions
Return True from __exit__ to suppress the exception. Return False (or nothing) to let it propagate.
class Ignore:
def __enter__(self): return self
def __exit__(self, *args): return True # swallow all exceptions
with Ignore():
1 / 0
print("continues here")A Database Connection Example
A classic use case: acquire a connection on enter, commit/rollback and close on exit.
class DBConn:
def __enter__(self):
self.conn = connect_db()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
self.conn.rollback()
else:
self.conn.commit()
self.conn.close()
return FalseA Timer Context Manager
Measure elapsed time by recording start in __enter__ and computing delta in __exit__.
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, *args):
self.elapsed = time.perf_counter() - self.start
print(f"Elapsed: {self.elapsed:.3f}s")
return False
with Timer():
sum(range(1_000_000))Nesting Context Managers
Multiple context managers can be combined on a single with line.
with open("in.txt") as src, open("out.txt", "w") as dst:
dst.write(src.read())Reusable vs Single-Use Managers
Context managers whose __enter__ allocates a fresh resource each time are reusable. Those that exhaust an internal state (like a lock held only once) may not be.
class Reusable:
def __enter__(self):
return []
def __exit__(self, *a):
return False
for _ in range(3):
with Reusable() as lst:
lst.append(1)
print(lst) # [1] each time__aenter__ and __aexit__ (Async)
For async context managers, define __aenter__ and __aexit__ coroutines and use async with.
class AsyncDB:
async def __aenter__(self):
self.conn = await connect()
return self.conn
async def __aexit__(self, *args):
await self.conn.close()
# async with AsyncDB() as conn:
# ...Wrapping File Objects
Python file objects already implement the context manager protocol — never call f.close() manually.
with open("data.txt", "r") as f:
data = f.read()
# file is closed here automatically
print(f.closed) # TrueImplementing a Lock
Thread locks are context managers: __enter__ acquires, __exit__ releases.
import threading
lock = threading.Lock()
def update_shared():
with lock:
# critical section
passQuick Check
What should __exit__ return to suppress an exception?
Recap
Implement __enter__ and __exit__ to create context managers. Return the resource from __enter__, handle cleanup and exception suppression in __exit__.
Frequently asked questions
Is the “__enter__ and __exit__ Protocol” lesson free?
Yes — the full text of “__enter__ and __exit__ Protocol” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.
What will I learn in “__enter__ and __exit__ Protocol”?
Build context managers using the dunder protocol. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Python Academy?
No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “__enter__ and __exit__ Protocol” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Python Academy lesson?
Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The with Statement in Depth
- __enter__ and __exit__ Protocol
- contextlib: @contextmanager
- Practical Context Manager Patterns