Add the stop_exception parameter to iter() and aiter()
The two-argument iter() only covers callables which report exhaustion by returning a special value. Many callables raise an exception instead — list.pop() and deque.popleft() raise IndexError, dict.popitem() raises KeyError, queue.get_nowait() raises Empty, asyncio.Queue.get() raises QueueShutDown after shutdown — and for them the sentinel form cannot be used at all. Every such loop is written by hand today.
This has been asked for several times: by Ram Rachum on python-ideas in February 2014, where Terry Reedy refined it from an exception in place of the sentinel into a separate third parameter; then as bpo-20663; and for aiter() on this forum in June. What follows is Reedy’s design, now with an implementation:
iter(iterable, /)
iter(callable, /, stop_value, *, stop_exception=StopIteration)
iter(callable, /, *, stop_exception)
for key, value in iter(d.popitem, stop_exception=KeyError):
process(key, value)
for item in iter(queue.get_nowait, stop_exception=Empty):
process(item)
stop_exception is an exception class or a tuple of exception classes, like the argument of an except clause. Either parameter can be given alone, or both together — whichever happens first ends the iteration. StopIteration keeps ending it in any case.
The same is proposed for aiter(), which has no callable form at all today. The callable is called and its result is awaited for every __anext__(), and StopAsyncIteration plays the role of StopIteration:
async for item in aiter(queue.get, stop_exception=QueueShutDown):
process(item)
Two things have changed since then. queue.Queue.shutdown() and asyncio.Queue.shutdown() were added, so ending a consumer loop on an exception is now the standard way to drain a queue. And gh-119154, which asked for asyncio.Queue.__aiter__, was declined in 2025 because no single __aiter__ fits the many ways a queue is consumed, and because a for-loop front-end hides where the blocking happens and which exception is caught. The conclusion there was that users should write a small wrapper instead — this is that wrapper, spelled once in the language rather than once per class, with the blocking call and the terminating exception both visible at the call site.
Implementation: GH-156298.
Is a PEP needed for this feature?