aiter()
Exactly what iter is for ordinary iterables, moved into the async world. Note it is NOT awaited — only anext is.
Common call
it = aiter(stream)
Returns
an async iterator — not a coroutine, so no await here
Replaces
calling stream.__aiter__() by hand
Watch out
aiter() is sync; anext() is what you await
aiter(async_iterableasync_iterable — An object implementing __aiter__ — an async generator, an async stream, or a class defining it.type: async iterable · required)
→ async iterator
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| async_iterable | async iterable | yes | An object implementing __aiter__ — an async generator, an async stream, or a class defining it. |
Return value
async iterator — The object returned by async_iterable.__aiter__(). Raises TypeError if the argument does not implement __aiter__.
Examples
1. Get an iterator
it = aiter(stream)
Returns
an async iterator2. Step it manually
it = aiter(stream)
first = await anext(it)
Returns
the first item3. No await on aiter
it = aiter(stream) # not awaited
Returns
returns immediately4. What async for does
async for x in stream:
...
Returns
calls aiter then anext repeatedly5. Wrong type
aiter([1, 2, 3])
Returns
TypeError: 'list' object is not an async iterable6. Idempotent
it = aiter(stream)
aiter(it) is it
Returns
True for a well-behaved iteratorPitfalls
1. aiter is not awaited, anext is
The asymmetry catches almost everyone. __aiter__ returns the iterator synchronously; only __anext__ is a coroutine. Awaiting aiter gives a TypeError about a non-awaitable.
Awaited wrongly
it = await aiter(stream)
TypeError: object async_generator can't be used in 'await' expression
Await only anext
it = aiter(stream) item = await anext(it)
correct
2. A plain iterable is not an async iterable
aiter needs __aiter__, which lists, generators and files do not have. There is no automatic bridge — wrap it in an async generator if you need one.
Sync list rejected
aiter([1, 2, 3])
TypeError: 'list' object is not an async iterable
Wrap it
async def to_async(xs): for x in xs: yield x aiter(to_async([1, 2, 3]))
an async iterator
3. No two-argument form
iter(callable, sentinel) has a second form; aiter does not. Passing two arguments is a TypeError rather than a sentinel-driven loop.
No sentinel form
aiter(read_chunk, b"")
TypeError: aiter expected 1 argument, got 2
Loop explicitly
while (chunk := await read_chunk()) != b"": ...
same effect, written out
4. Python 3.10 and newer only
Async iteration itself dates from 3.5, but the aiter and anext builtins only arrived in 3.10. On older versions call the dunder directly.
Fails on 3.9
aiter(stream)
NameError: name 'aiter' is not defined
Call the dunder
it = stream.__aiter__()
works from 3.5
When to use
Use it
- Stepping an async stream manually rather than with async for
- Writing generic code that must accept any async iterable
- Implementing helpers such as an async version of zip or islice
Reach for something else
- A simple loop → async for is clearer and handles the protocol for you
- Synchronous iterables → iter
- Supporting Python 3.9 or older without a fallback
Notes
Complexity
O(1) — one call to __aiter__
Return
An async iterator; calling aiter on one should return it unchanged
CPython impl
Python/bltinmodule.c :: builtin_aiter
Memory
No allocation beyond whatever __aiter__ creates
Thread-safe
Bound to its event loop — do not share an async iterator across loops
FAQ
Because getting an iterator does no I/O — it just hands back an object. Only advancing it can block, which is why __anext__ is the coroutine and __aiter__ is an ordinary method.
it = aiter(stream) # sync item = await anext(it) # async
History
3.5
Async iteration protocol introduced by PEP 492 (__aiter__ and __anext__).
3.10
aiter and anext added as builtins, mirroring iter and next.