Skip to content

Commit ce35092

Browse files
committed
Implement aiter() and anext() using sync methods only
1 parent ad12116 commit ce35092

1 file changed

Lines changed: 63 additions & 15 deletions

File tree

Lib/operator.py

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -429,17 +429,46 @@ def aiter(obj, sentinel=_NOT_PROVIDED):
429429
if not callable(obj):
430430
raise TypeError(f'aiter expected an async callable, got {type(obj)}')
431431

432-
async def ait():
433-
while True:
434-
value = await obj()
435-
if value == sentinel:
436-
break
437-
yield value
432+
return _aiter_callable(obj, sentinel)
438433

439-
return ait()
440434

435+
class _aiter_callable:
436+
__slots__ = ('acallable', 'sentinel')
441437

442-
async def anext(async_iterator, default=_NOT_PROVIDED):
438+
def __init__(self, acallable, sentinel):
439+
self.acallable = acallable
440+
self.sentinel = sentinel
441+
442+
def __aiter__(self):
443+
return self
444+
445+
def __anext__(self):
446+
return _aiter_anext(self.acallable().__await__(), self.sentinel)
447+
448+
449+
class _aiter_anext:
450+
__slots__ = ('iterator', 'sentinel')
451+
452+
def __init__(self, iterator, sentinel):
453+
self.iterator = iterator
454+
self.sentinel = sentinel
455+
456+
def __await__(self):
457+
return self
458+
459+
def __iter__(self):
460+
return self
461+
462+
def __next__(self):
463+
try:
464+
return next(self.iterator)
465+
except StopIteration as end:
466+
if end.value == self.sentinel:
467+
raise StopAsyncIteration(end.value) from None
468+
raise
469+
470+
471+
def anext(async_iterator, default=_NOT_PROVIDED):
443472
"""anext(async_iterator[, default])
444473
445474
Return the next item from the async iterator.
@@ -449,13 +478,32 @@ async def anext(async_iterator, default=_NOT_PROVIDED):
449478
from collections.abc import AsyncIterator
450479
if not isinstance(async_iterator, AsyncIterator):
451480
raise TypeError(f'anext expected an AsyncIterator, got {type(async_iterator)}')
452-
anxt = type(async_iterator).__anext__
453-
try:
454-
return await anxt(async_iterator)
455-
except StopAsyncIteration:
456-
if default is _NOT_PROVIDED:
457-
raise
458-
return default
481+
anxt = type(async_iterator).__anext__(async_iterator)
482+
483+
if default is _NOT_PROVIDED:
484+
return anxt
485+
486+
return _anext_default(anxt, default)
487+
488+
489+
class _anext_default:
490+
__slots__ = ('iterator', 'default')
491+
492+
def __init__(self, iterator, default):
493+
self.iterator = iterator
494+
self.default = default
495+
496+
def __await__(self):
497+
return self
498+
499+
def __iter__(self):
500+
return self
501+
502+
def __next__(self):
503+
try:
504+
return next(self.iterator)
505+
except StopAsyncIteration:
506+
raise StopIteration(self.default) from None
459507

460508

461509
try:

0 commit comments

Comments
 (0)