Back to Blog
Python

Python anext: Next Item from Async Iterator

python **anext**: Learn how to use Python's anext() to fetch the next item from async iterators and generators, including default values and error handling.

asynciteratorsgeneratorsasynciopython
Illustration of Python's anext() function retrieving the next item from an async iterator, with a default value fallback.

python anext requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

Python's anext() built-in is the async counterpart of next(). It returns the next item from an async iterator, and it became a built-in in Python 3.10. If you've worked with async for loops, you've likely used an async iterator without needing to call anext() directly. But when you need to pull items one at a time, handle a default value, or control the iteration flow manually, anext() is the tool.

Basic Syntax and Minimal Example

The signature of anext() is:

anext(async_iterator, default=...)

It takes an async iterator as the first argument. The optional second argument is a default value returned when the iterator is exhausted. Without a default, it raises StopAsyncIteration.

Here's the simplest usage with an async generator:

import asyncio async def counter(): for i in range(3): yield i async def main(): gen = counter() print(await anext(gen)) # 0 print(await anext(gen)) # 1 print(await anext(gen)) # 2 # next call would raise StopAsyncIteration asyncio.run(main())

Because anext() is a coroutine, you must await it. That's the key difference from next(), which is synchronous.

Using a Default Value to Avoid StopAsyncIteration

When you don't know whether the iterator has more items, pass a default. This is useful when you're reading from a stream or a queue and want to fall back to a sentinel value.

async def main(): gen = counter() print(await anext(gen, None)) # 0 print(await anext(gen, None)) # 1 print(await anext(gen, None)) # 2 print(await anext(gen, None)) # None

The default is returned when the iterator is exhausted, just like next(iterator, default). Note that the default is not evaluated lazily; it's a regular argument.

Handling StopAsyncIteration Explicitly

If you don't provide a default, you must catch StopAsyncIteration to avoid an unhandled exception. This is common when you're implementing a custom async iterator or when you want to break out of a manual loop.

async def main(): gen = counter() while True: try: item = await anext(gen) except StopAsyncIteration: break print(item)

This pattern is equivalent to a for loop over an async iterator, but it gives you more control, for example, if you need to conditionally skip items or stop early.

anext() with Async Iterators vs Async Generators

anext() works with any object that implements __anext__(). Async generators are the most common, but you can also create custom async iterators by defining __aiter__ and __anext__.

class AsyncRange: def __init__(self, start, end): self.current = start self.end = end def __aiter__(self): return self async def __anext__(self): if self.current >= self.end: raise StopAsyncIteration value = self.current self.current += 1 return value

You can use anext() on instances of this class the same way:

async def main(): ar = AsyncRange(1, 4) print(await anext(ar)) # 1 print(await anext(ar)) # 2 print(await anext(ar)) # 3

The distinction matters when you're designing an API: an async generator is a compact way to create an async iterator, but a custom class gives you full control over state and cleanup.

Common Mistakes and Edge Cases

One frequent mistake is calling anext() on a regular iterator. It will fail because a sync iterator doesn't have __anext__. You must use next() for that. Conversely, calling next() on an async iterator raises TypeError because it's not a sync iterator.

Another edge case: anext() expects an async iterator, not a coroutine or an awaitable. Passing an async generator object is fine, but passing a coroutine object will raise TypeError.

Also, be careful when using anext() on an async iterator that is already exhausted. Without a default, it raises StopAsyncIteration every time, which is expected. With a default, it returns the default each time.

Performance and Resource Considerations

anext() is a coroutine, so each call involves an awaitable creation and an event loop scheduling step. In most applications, this overhead is negligible compared to the actual I/O or computation inside the iterator. However, if you're iterating over a very large number of items and performance is critical, consider whether a for loop or a bulk operation might be more efficient. The manual anext() pattern is best when you need fine-grained control, not for hot loops where you're simply consuming all items.

Another resource concern is cancellation. If a task that's awaiting anext() is cancelled, the cancellation propagates into the iterator. If your async generator has finally blocks, they will run. This is the same behavior as with async for, so you don't need special handling unless you're managing external resources.

Compatibility and Python Version Requirements

anext() was added in Python 3.10. If you're supporting Python 3.9 or earlier, you can use the equivalent from the more-itertools package or define your own helper:

async def anext_default(iterator, default=None): try: return await iterator.__anext__() except StopAsyncIteration: return default

But for modern code, the built-in is cleaner. Also note that anext() is a built-in, so it's always available without an import. This makes it a natural choice for library code that needs to fetch the next item from an async iterator without adding a dependency.

When you're writing an async iterator yourself, make sure your __anext__ method is a coroutine (i.e., defined with async def). If it's a regular method that returns a value, anext() will still work because it awaits the result, but the method won't be able to perform asynchronous operations. In practice, you'll almost always define it as async def.

python **anext**: Practical Usage and Code Examples | RYUSLOG DEV