Async Context Managers and Iterators
Implement async with and async for protocols.
Async Context Managers and Iterators is a free Python Academy lesson on CoddyKit — lesson 3 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.
async with Statement
Use async with for context managers whose setup/teardown involves awaiting I/O. The managed object must implement __aenter__ and __aexit__.
import asyncio
class AsyncFile:
async def __aenter__(self):
print("open")
return self
async def __aexit__(self, *args):
print("close")
async def main():
async with AsyncFile() as f:
print("using")
asyncio.run(main())__aenter__ and __aexit__
Both are coroutines. __aenter__ is awaited on entry; __aexit__ is awaited on exit even if an exception occurred.
import asyncio
class DBSession:
async def __aenter__(self):
self.conn = await async_connect()
return self.conn
async def __aexit__(self, exc_type, exc_val, exc_tb):
if exc_type:
await self.conn.rollback()
else:
await self.conn.commit()
await self.conn.close()
return False@asynccontextmanager
contextlib.asynccontextmanager lets you write async context managers as async generator functions.
from contextlib import asynccontextmanager
import asyncio
@asynccontextmanager
async def managed_resource():
print("acquire")
try:
yield {"status": "ready"}
finally:
print("release")
async def main():
async with managed_resource() as r:
print(r["status"])
asyncio.run(main())async for Statement
async for iterates over an async iterable — one that implements __aiter__ and __anext__. Each iteration may involve I/O.
import asyncio
class AsyncCounter:
def __init__(self, n): self.n, self.i = n, 0
def __aiter__(self): return self
async def __anext__(self):
if self.i >= self.n: raise StopAsyncIteration
await asyncio.sleep(0)
self.i += 1
return self.i
async def main():
async for val in AsyncCounter(3):
print(val)
asyncio.run(main())Async Generators
An async def function containing yield is an async generator. Use async for to consume it.
import asyncio
async def ticker(n):
for i in range(n):
await asyncio.sleep(1)
yield i
async def main():
async for val in ticker(3):
print(val) # 0, 1, 2 with 1-s pauses
asyncio.run(main())aiofiles for Async File I/O
The aiofiles library wraps file operations in async context managers and async iterators.
# pip install aiofiles
import aiofiles, asyncio
async def main():
async with aiofiles.open("data.txt", "r") as f:
async for line in f:
print(line.strip())aiohttp Client Session
aiohttp.ClientSession is an async context manager for making concurrent HTTP requests.
# pip install aiohttp
import aiohttp, asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
return await resp.json()
asyncio.run(fetch("https://api.example.com/data"))Multiple Async Context Managers
Stack multiple async with clauses on one line (Python 3.10+ parenthesised form).
import asyncio
async def main():
async with (
open_db() as db,
open_cache() as cache,
):
data = await db.fetch("SELECT 1")
await cache.set("key", data)AsyncExitStack
contextlib.AsyncExitStack manages a dynamic set of async context managers.
from contextlib import AsyncExitStack
import asyncio
async def main():
async with AsyncExitStack() as stack:
conn1 = await stack.enter_async_context(connect("db1"))
conn2 = await stack.enter_async_context(connect("db2"))
await process(conn1, conn2)Testing Async Code with pytest-asyncio
pytest-asyncio lets you write async test functions with the @pytest.mark.asyncio marker.
# pip install pytest-asyncio
import pytest, asyncio
async def fetch(): return 42
@pytest.mark.asyncio
async def test_fetch():
result = await fetch()
assert result == 42Async Iterator Protocol Summary
An object is an async iterable if it has __aiter__. It is an async iterator if it also has __anext__. Async generators implement both automatically.
import asyncio
async def gen():
yield 1
yield 2
async def main():
g = gen()
print(await g.__anext__()) # 1
print(await g.__anext__()) # 2Quick Check
Which dunder methods must an object implement to be used with async with?
Recap
Use async with for resources that need async setup/teardown. Use async for for iterables that produce values asynchronously. Async generators simplify async iterator creation. Libraries like aiofiles and aiohttp provide async-native file and HTTP operations.
Frequently asked questions
Is the “Async Context Managers and Iterators” lesson free?
Yes — the full text of “Async Context Managers and Iterators” 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 “Async Context Managers and Iterators”?
Implement async with and async for protocols. 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 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Async Context Managers and Iterators” 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
- Coroutines and the event loop
- await, Tasks, and Gathering
- Async Context Managers and Iterators
- Async I/O Patterns in Production