Skip to content

Commit d7bddaa

Browse files
authored
Make chain a class like the standard sync chain (#103)
* Make `chain` a class like the standard sync `chain` Fixes [GH#102](#102). Signed-off-by: William So <[email protected]>
1 parent cecf2cd commit d7bddaa

File tree

1 file changed

+26
-21
lines changed

1 file changed

+26
-21
lines changed

asyncstdlib/itertools.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -141,35 +141,40 @@ async def accumulate(iterable, function, *, initial):
141141
yield value
142142

143143

144-
async def chain(*iterables: AnyIterable[T]) -> AsyncIterator[T]:
144+
class chain(AsyncIterator[T]):
145145
"""
146146
An :term:`asynchronous iterator` flattening values from all ``iterables``
147147
148148
The resulting iterator consecutively iterates over and yields all values from
149149
each of the ``iterables``. This is similar to converting all ``iterables`` to
150150
sequences and concatenating them, but lazily exhausts each iterable.
151151
"""
152-
for iterable in iterables:
153-
async with ScopedIter(iterable) as iterator:
154-
async for item in iterator:
155-
yield item
156-
157-
158-
@public_module(__name__, "chain.from_iterable")
159-
async def chain_from_iterable(
160-
iterable: AnyIterable[AnyIterable[T]],
161-
) -> AsyncIterator[T]:
162-
"""
163-
Alternate constructor for :py:func:`~.chain` that lazily exhausts iterables as well
164-
"""
165-
async with ScopedIter(iterable) as iterables:
166-
async for sub_iterable in iterables:
167-
async with ScopedIter(sub_iterable) as iterator:
168-
async for item in iterator:
169-
yield item
170-
171152

172-
chain.from_iterable = chain_from_iterable # type: ignore
153+
__slots__ = ("_impl",)
154+
155+
def __init__(self, *iterables: AnyIterable[T]):
156+
async def impl() -> AsyncIterator[T]:
157+
for iterable in iterables:
158+
async with ScopedIter(iterable) as iterator:
159+
async for item in iterator:
160+
yield item
161+
162+
self._impl = impl()
163+
164+
@staticmethod
165+
async def from_iterable(iterable: AnyIterable[AnyIterable[T]]) -> AsyncIterator[T]:
166+
"""
167+
Alternate constructor for :py:func:`~.chain` that lazily exhausts
168+
iterables as well
169+
"""
170+
async with ScopedIter(iterable) as iterables:
171+
async for sub_iterable in iterables:
172+
async with ScopedIter(sub_iterable) as iterator:
173+
async for item in iterator:
174+
yield item
175+
176+
def __anext__(self) -> Awaitable[T]:
177+
return self._impl.__anext__()
173178

174179

175180
async def compress(

0 commit comments

Comments
 (0)