Skip to content

[3.13] Misc improvements to the itertools docs (gh-119040) #119045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 26 additions & 35 deletions Doc/library/itertools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -800,6 +796,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
.. testcode::

import collections
import contextlib
import functools
import math
import operator
Expand Down Expand Up @@ -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:
Expand Down
Loading