Misc improvements to the itertools docs (gh-119040)

This commit is contained in:
Raymond Hettinger 2024-05-14 10:18:19 -05:00 committed by GitHub
parent a9328e2b6e
commit 7a97ee570f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 26 additions and 35 deletions

View File

@ -122,15 +122,15 @@ loops that truncate the stream.
# accumulate([1,2,3,4,5]) → 1 3 6 10 15
# accumulate([1,2,3,4,5], initial=100) → 100 101 103 106 110 115
# accumulate([1,2,3,4,5], operator.mul) → 1 2 6 24 120
it = iter(iterable)
iterator = iter(iterable)
total = initial
if initial is None:
try:
total = next(it)
total = next(iterator)
except StopIteration:
return
yield total
for element in it:
for element in iterator:
total = func(total, element)
yield total
@ -218,9 +218,8 @@ loops that truncate the stream.
def chain(*iterables):
# chain('ABC', 'DEF') → A B C D E F
for it in iterables:
for element in it:
yield element
for iterable in iterables:
yield from iterable
.. classmethod:: chain.from_iterable(iterable)
@ -230,9 +229,8 @@ loops that truncate the stream.
def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) → A B C D E F
for it in iterables:
for element in it:
yield element
for iterable in iterables:
yield from iterable
.. function:: combinations(iterable, r)
@ -696,24 +694,22 @@ loops that truncate the stream.
Return *n* independent iterators from a single iterable.
The following Python code helps explain what *tee* does (although the actual
implementation is more complex and uses only a single underlying
:abbr:`FIFO (first-in, first-out)` queue)::
Roughly equivalent to::
def tee(iterable, n=2):
it = iter(iterable)
deques = [collections.deque() for i in range(n)]
def gen(mydeque):
while True:
if not mydeque: # when the local deque is empty
try:
newval = next(it) # fetch a new value and
except StopIteration:
return
for d in deques: # load it to all the deques
d.append(newval)
yield mydeque.popleft()
return tuple(gen(d) for d in deques)
iterator = iter(iterable)
empty_link = [None, None] # Singly linked list: [value, link]
return tuple(_tee(iterator, empty_link) for _ in range(n))
def _tee(iterator, link):
while True:
if link[1] is None:
try:
link[:] = [next(iterator), [None, None]]
except StopIteration:
return
value, link = link
yield value
Once a :func:`tee` has been created, the original *iterable* should not be
used anywhere else; otherwise, the *iterable* could get advanced without
@ -743,9 +739,9 @@ loops that truncate the stream.
return
while True:
values = []
for i, it in enumerate(iterators):
for i, iterator in enumerate(iterators):
try:
value = next(it)
value = next(iterator)
except StopIteration:
num_active -= 1
if not num_active:
@ -800,6 +796,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
.. testcode::
import collections
import contextlib
import functools
import math
import operator
@ -942,32 +939,26 @@ and :term:`generators <generator>` which incur interpreter overhead.
# iter_index('AABCADEAF', 'A') → 0 1 4 7
seq_index = getattr(iterable, 'index', None)
if seq_index is None:
# Path for general iterables
iterator = islice(iterable, start, stop)
for i, element in enumerate(iterator, start):
if element is value or element == value:
yield i
else:
# Path for sequences with an index() method
stop = len(iterable) if stop is None else stop
i = start
try:
with contextlib.suppress(ValueError):
while True:
yield (i := seq_index(value, i, stop))
i += 1
except ValueError:
pass
def iter_except(func, exception, first=None):
"Convert a call-until-exception interface to an iterator interface."
# iter_except(d.popitem, KeyError) → non-blocking dictionary iterator
try:
with contextlib.suppress(exception):
if first is not None:
yield first()
while True:
yield func()
except exception:
pass
The following recipes have a more mathematical flavor: