Skip to content

Commit 7a97ee5

Browse files
authored
Misc improvements to the itertools docs (gh-119040)
1 parent a9328e2 commit 7a97ee5

File tree

1 file changed

+26
-35
lines changed

1 file changed

+26
-35
lines changed

Diff for: Doc/library/itertools.rst

+26-35
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,15 @@ loops that truncate the stream.
122122
# accumulate([1,2,3,4,5]) → 1 3 6 10 15
123123
# accumulate([1,2,3,4,5], initial=100) → 100 101 103 106 110 115
124124
# accumulate([1,2,3,4,5], operator.mul) → 1 2 6 24 120
125-
it = iter(iterable)
125+
iterator = iter(iterable)
126126
total = initial
127127
if initial is None:
128128
try:
129-
total = next(it)
129+
total = next(iterator)
130130
except StopIteration:
131131
return
132132
yield total
133-
for element in it:
133+
for element in iterator:
134134
total = func(total, element)
135135
yield total
136136

@@ -218,9 +218,8 @@ loops that truncate the stream.
218218

219219
def chain(*iterables):
220220
# chain('ABC', 'DEF') → A B C D E F
221-
for it in iterables:
222-
for element in it:
223-
yield element
221+
for iterable in iterables:
222+
yield from iterable
224223

225224

226225
.. classmethod:: chain.from_iterable(iterable)
@@ -230,9 +229,8 @@ loops that truncate the stream.
230229

231230
def from_iterable(iterables):
232231
# chain.from_iterable(['ABC', 'DEF']) → A B C D E F
233-
for it in iterables:
234-
for element in it:
235-
yield element
232+
for iterable in iterables:
233+
yield from iterable
236234

237235

238236
.. function:: combinations(iterable, r)
@@ -696,24 +694,22 @@ loops that truncate the stream.
696694

697695
Return *n* independent iterators from a single iterable.
698696

699-
The following Python code helps explain what *tee* does (although the actual
700-
implementation is more complex and uses only a single underlying
701-
:abbr:`FIFO (first-in, first-out)` queue)::
697+
Roughly equivalent to::
702698

703699
def tee(iterable, n=2):
704-
it = iter(iterable)
705-
deques = [collections.deque() for i in range(n)]
706-
def gen(mydeque):
707-
while True:
708-
if not mydeque: # when the local deque is empty
709-
try:
710-
newval = next(it) # fetch a new value and
711-
except StopIteration:
712-
return
713-
for d in deques: # load it to all the deques
714-
d.append(newval)
715-
yield mydeque.popleft()
716-
return tuple(gen(d) for d in deques)
700+
iterator = iter(iterable)
701+
empty_link = [None, None] # Singly linked list: [value, link]
702+
return tuple(_tee(iterator, empty_link) for _ in range(n))
703+
704+
def _tee(iterator, link):
705+
while True:
706+
if link[1] is None:
707+
try:
708+
link[:] = [next(iterator), [None, None]]
709+
except StopIteration:
710+
return
711+
value, link = link
712+
yield value
717713

718714
Once a :func:`tee` has been created, the original *iterable* should not be
719715
used anywhere else; otherwise, the *iterable* could get advanced without
@@ -743,9 +739,9 @@ loops that truncate the stream.
743739
return
744740
while True:
745741
values = []
746-
for i, it in enumerate(iterators):
742+
for i, iterator in enumerate(iterators):
747743
try:
748-
value = next(it)
744+
value = next(iterator)
749745
except StopIteration:
750746
num_active -= 1
751747
if not num_active:
@@ -800,6 +796,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
800796
.. testcode::
801797

802798
import collections
799+
import contextlib
803800
import functools
804801
import math
805802
import operator
@@ -942,32 +939,26 @@ and :term:`generators <generator>` which incur interpreter overhead.
942939
# iter_index('AABCADEAF', 'A') → 0 1 4 7
943940
seq_index = getattr(iterable, 'index', None)
944941
if seq_index is None:
945-
# Path for general iterables
946942
iterator = islice(iterable, start, stop)
947943
for i, element in enumerate(iterator, start):
948944
if element is value or element == value:
949945
yield i
950946
else:
951-
# Path for sequences with an index() method
952947
stop = len(iterable) if stop is None else stop
953948
i = start
954-
try:
949+
with contextlib.suppress(ValueError):
955950
while True:
956951
yield (i := seq_index(value, i, stop))
957952
i += 1
958-
except ValueError:
959-
pass
960953

961954
def iter_except(func, exception, first=None):
962955
"Convert a call-until-exception interface to an iterator interface."
963956
# iter_except(d.popitem, KeyError) → non-blocking dictionary iterator
964-
try:
957+
with contextlib.suppress(exception):
965958
if first is not None:
966959
yield first()
967960
while True:
968961
yield func()
969-
except exception:
970-
pass
971962

972963

973964
The following recipes have a more mathematical flavor:

0 commit comments

Comments
 (0)