The itertools library¶
The asyncstdlib.itertools library implements
Python’s itertools for (async) functions and (async) iterables.
Note
Only functions which benefit from an explicit async implementation are provided.
Other functions from itertools can be turned asynchronous using iter(),
e.g. asyncstdlib.iter(itertools.count(5)).
Note
To avoid leaking resources, all utilities in this module explicitly close their
iterable arguments when done.
This can be unexpected for non-exhausting utilities such as dropwhile()
and may require explicit scoping.
See the guide on Iterator Scoping for details and usage examples.
Infinite iterators¶
- async for :T in cycle(iterable: (async) iter T)[source]¶
An asynchronous iterator indefinitely iterating over
iterableThis lazily exhausts
iterableon its first pass, and recalls items from an internal buffer on subsequent passes. Ifiterableis empty, the resulting iterator terminates immediately.This means items from
iterableare provided immediately as they become available, even if later items are not ready yet. Subsequent passes directly provide items, without replicating any delays of the originaliterable. All items produced byiterableare stored internally, which may consume significant memory.
Iterator merging¶
- async for :T in chain(*iterables: (async) iter T)[source]¶
An asynchronous iterator flattening values from all
iterablesThe resulting iterator consecutively iterates over and yields all values from each of the
iterables. This is similar to converting alliterablesto sequences and concatenating them, but lazily exhausts each iterable.The
chainassumes ownership of itsiterablesand closes them reliably when thechainis closed. Pass theiterablesvia atupletochain.from_iterableto avoid closing all iterables but those already processed.
- async for :T in chain.from_iterable(iterable: (async) iter (async) iter T)[source]¶
Alternate constructor for
chain()that lazily exhausts theiterableof iterables as wellThis is suitable for chaining iterables from a lazy or infinite
iterable. In turn, closing thechainonly closes those iterables already fetched fromiterable.
- async for :(T or S, ...) in zip_longest(*iterables: (async) iter T, fillvalue: S = None)[source]¶
Create an async iterator that aggregates elements from each of the (async) iterables
The next element of
zip_longestis atupleof the next element of each of itsiterables. As soon as all of itsiterablesare exhausted,zip_longestis exhausted as well. Shorter iterables are padded byfillvalue. This means that ifzip_longestreceives niterables, with the longest having m elements, it becomes a generator m-times producing an n-tuple.If
iterablesis empty, thezip_longestiterator is empty as well. Multipleiterablesmay be mixed regular and async iterables.
Iterator filtering¶
- async for :T in compress(data: (async) iter T, selectors: (async) iter T)[source]¶
An asynchronous iterator for items of
datawith trueselectorsLazily iterates both
dataandselectorspairwise, yielding onlydataitems for which their pairedselectorsevaluate as true. Roughly equivalent to:async def compress(data, selectors): return (item async for item, select in zip(data, selectors) if select)
- async for :T in dropwhile(predicate: (T) → (await) bool, iterable: (async) iter T)[source]¶
Yield items from
iterableafterpredicate(item)is no longer trueThis lazily iterates over
iterable, discarding items as long as evaluatingpredicatefor the current item is true. As soon aspredicateevaluates as true for the current item, this item is yielded. All subsequent items are yielded immediately as they become available, without evaluatingpredicatefor them.
- async for :T in filterfalse(predicate: None | (T) → (await) bool, iterable: (async) iter T)[source]¶
Yield items from
iterablefor whichpredicate(item)is false.If
predicateisNone, yield any items which are false.
- async for :T in takewhile(predicate: (T) → (await) bool, iterable: (async) iter T)[source]¶
Yield items from
iterableas long aspredicate(item)is trueThis lazily iterates over
iterable, yielding items as long as evaluatingpredicatefor the current item is true. As soon aspredicateevaluates as false for the current item, no more items are yielded. Note that ifiterableis a single-use iterator, the item is available neither fromiterablenortakewhileand effectively discarded.
- async for :T in islice(iterable: (async) iter T, stop: int)[source]
- async for :T in islice(iterable: (async) iter T, start: int, stop: int, step: int =m1)[source]¶
An asynchronous iterator over items from
iterablein asliceAside from the iterable, this function accepts one to three parameters as understood by
slice: a single parameterstop, or up to three parametersstart, stop [, step]. The firststartitems ofiterableare discarded. Afterwards, eachstepitem is yielded until a total ofstopitems have been fetched. This effectively is a lazy, asynchronous version ofiterable[start:stop:step].
Iterator transforming¶
- async for :T in accumulate(iterable: (async) iter T, function: (T, T) → (await) T = add[, initial: T])[source]¶
An asynchronous iterator on the running reduction of
iterable- Raises:
TypeError – if
iterableis empty andinitialis not given
This is conceptually equivalent to
reduce()in that it applies a reductionfunctioniteratively on theiterable. However, the iterator yields the running reduction value as each value is fetched fromiterable.The
functiondefaults tooperator.add, providing a running sum. If aninitialvalue is provided, it is the first value processed and yielded. Provided that all parameters are given and valid, this is roughly equivalent to:async def accumulate(iterable, function, *, initial): current = initial yield current async for value in accumulate: current = await function(current, value) yield current
- async for :T in starmap(function: (*A) → (await) T, iterable: (async) iter (A, ...))[source]¶
An asynchronous iterator applying a function to arguments from an iterable
This is conceptually similar to
map(), but applies a single iterable of multiple arguments instead of multiple iterables of a single argument each. The same way thatfunction(a, b)can be generalized tomap(function, iter_a, iter_b),function(*c)can be generalized tostarmap(function, iter_c).
Iterator splitting¶
- for :(async iter T, ...) in tee(iterable: (async) iter T, n: int = 2[, *, lock: async with Any])¶
Create
nseparate asynchronous iterators overiterableThis splits a single
iterableinto multiple iterators, each providing the same items in the same order. All child iterators may advance separately but share the same items fromiterable– when the most advanced iterator retrieves an item, it is buffered until the least advanced iterator has yielded it as well. Ateeworks lazily and can handle an infiniteiterable, provided that all iterators advance.async def derivative(sensor_data): previous, current = a.tee(sensor_data, n=2) await a.anext(previous) # advance one iterator return a.map(operator.sub, previous, current)
Unlike
itertools.tee(),tee()returns a custom type instead of atuple. Like a tuple, it can be indexed, iterated and unpacked to get the child iterators. In addition, itsaclose()method immediately closes all children, and it can be used in anasync withcontext for the same effect.If
iterableis an iterator and read elsewhere,teewill not provide these items. Also,teemust internally buffer each item until the last iterator has yielded it; if the most and least advanced iterator differ by most data, using alistis more efficient (but not lazy).If the underlying iterable is concurrency safe (
anextmay be awaited concurrently) the resulting iterators are concurrency safe as well. Otherwise, the iterators are safe if there is only ever one single “most advanced” iterator. To enforce sequential use ofanext, provide alock- e.g. anasyncio.Lockinstance in anasyncioapplication - and access is automatically synchronised.Added in version 3.10.5: The
lockkeyword parameter.
- async for :(T, T) in pairwise(iterable: (async) iter T)[source]¶
Yield successive, overlapping pairs of items from
iterablePairs are yielded as the newest item is available from
iterable. No pair is emitted ifiterablehas one or zero items; however, if there is one itempairwisewill wait for and consume it before finishing.Added in version 3.10.0.
- async for :T in batched(iterable: (async) iter T, n: int, strict: bool = False)[source]¶
Batch the
iterableto tuples of the lengthn.This lazily exhausts
iterableand returns each batch as soon as it is ready. IfstrictisTrueand the last batch is smaller thann,ValueErroris raised.Added in version 3.11.0.
Added in version 3.13.0: The
strictparameter.
- async for :(T, async iter T) in groupby(iterable: (async) iter T)
- async for :(R, async iter T) in groupby(iterable: (async) iter T, key: (T) → (await) R)¶
Create an async iterator over consecutive keys and groups from the (async) iterable
The groups generated by
groupbyare consecutive with respect to the original (async) iterable. That is, multiple groups may have the same key if there is any intermediate group with different key. For example, the iterable1, 1, 1, 2, 2, 1is split into the groups1, 2, 1.The async iterator returned by
groupbyas well as the async iterators of each group share the same underlying iterator. This means that previous groups are no longer accessible if thegroubpyiterator advances to the next group. In specific, it is not safe to concurrently advance both thegroupbyiterator itself and any of its group iterators.In contrast to the original
itertools.groupby(), it is generally not useful to sortiterablebykeybeforehand. Since both values and keys are required up-front for sorting, this loses the advantage of asynchronous, lazy iteration and evaluation.Added in version 1.1.0.