Skip to content

Commit

Permalink
Misc improvements to the itertools docs (pythongh-119040)
Browse files Browse the repository at this point in the history
(cherry picked from commit 7a97ee5)

Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
  • Loading branch information
rhettinger authored and miss-islington committed May 14, 2024
1 parent 87f683e commit 0e20960
Showing 1 changed file with 26 additions and 35 deletions.
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

0 comments on commit 0e20960

Please sign in to comment.