Skip to content

Commit bac277f

Browse files
[3.12] Misc improvements to the itertools docs (gh-119040) (#119044)
1 parent 71ec353 commit bac277f

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

@@ -210,9 +210,8 @@ loops that truncate the stream.
210210

211211
def chain(*iterables):
212212
# chain('ABC', 'DEF') → A B C D E F
213-
for it in iterables:
214-
for element in it:
215-
yield element
213+
for iterable in iterables:
214+
yield from iterable
216215

217216

218217
.. classmethod:: chain.from_iterable(iterable)
@@ -222,9 +221,8 @@ loops that truncate the stream.
222221

223222
def from_iterable(iterables):
224223
# chain.from_iterable(['ABC', 'DEF']) → A B C D E F
225-
for it in iterables:
226-
for element in it:
227-
yield element
224+
for iterable in iterables:
225+
yield from iterable
228226

229227

230228
.. function:: combinations(iterable, r)
@@ -688,24 +686,22 @@ loops that truncate the stream.
688686

689687
Return *n* independent iterators from a single iterable.
690688

691-
The following Python code helps explain what *tee* does (although the actual
692-
implementation is more complex and uses only a single underlying
693-
:abbr:`FIFO (first-in, first-out)` queue)::
689+
Roughly equivalent to::
694690

695691
def tee(iterable, n=2):
696-
it = iter(iterable)
697-
deques = [collections.deque() for i in range(n)]
698-
def gen(mydeque):
699-
while True:
700-
if not mydeque: # when the local deque is empty
701-
try:
702-
newval = next(it) # fetch a new value and
703-
except StopIteration:
704-
return
705-
for d in deques: # load it to all the deques
706-
d.append(newval)
707-
yield mydeque.popleft()
708-
return tuple(gen(d) for d in deques)
692+
iterator = iter(iterable)
693+
empty_link = [None, None] # Singly linked list: [value, link]
694+
return tuple(_tee(iterator, empty_link) for _ in range(n))
695+
696+
def _tee(iterator, link):
697+
while True:
698+
if link[1] is None:
699+
try:
700+
link[:] = [next(iterator), [None, None]]
701+
except StopIteration:
702+
return
703+
value, link = link
704+
yield value
709705

710706
Once a :func:`tee` has been created, the original *iterable* should not be
711707
used anywhere else; otherwise, the *iterable* could get advanced without
@@ -735,9 +731,9 @@ loops that truncate the stream.
735731
return
736732
while True:
737733
values = []
738-
for i, it in enumerate(iterators):
734+
for i, iterator in enumerate(iterators):
739735
try:
740-
value = next(it)
736+
value = next(iterator)
741737
except StopIteration:
742738
num_active -= 1
743739
if not num_active:
@@ -792,6 +788,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
792788
.. testcode::
793789

794790
import collections
791+
import contextlib
795792
import functools
796793
import math
797794
import operator
@@ -934,32 +931,26 @@ and :term:`generators <generator>` which incur interpreter overhead.
934931
# iter_index('AABCADEAF', 'A') → 0 1 4 7
935932
seq_index = getattr(iterable, 'index', None)
936933
if seq_index is None:
937-
# Path for general iterables
938934
iterator = islice(iterable, start, stop)
939935
for i, element in enumerate(iterator, start):
940936
if element is value or element == value:
941937
yield i
942938
else:
943-
# Path for sequences with an index() method
944939
stop = len(iterable) if stop is None else stop
945940
i = start
946-
try:
941+
with contextlib.suppress(ValueError):
947942
while True:
948943
yield (i := seq_index(value, i, stop))
949944
i += 1
950-
except ValueError:
951-
pass
952945

953946
def iter_except(func, exception, first=None):
954947
"Convert a call-until-exception interface to an iterator interface."
955948
# iter_except(d.popitem, KeyError) → non-blocking dictionary iterator
956-
try:
949+
with contextlib.suppress(exception):
957950
if first is not None:
958951
yield first()
959952
while True:
960953
yield func()
961-
except exception:
962-
pass
963954

964955

965956
The following recipes have a more mathematical flavor:

0 commit comments

Comments
 (0)