Skip to content

Commit 2d70067

Browse files
authored
[3.12] Misc improvements to the docs for itertools (gh-119532)
1 parent 30679a6 commit 2d70067

File tree

1 file changed

+55
-55
lines changed

1 file changed

+55
-55
lines changed

Doc/library/itertools.rst

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ loops that truncate the stream.
134134
total = func(total, element)
135135
yield total
136136

137-
There are a number of uses for the *func* argument. It can be set to
137+
The *func* argument can be set to
138138
:func:`min` for a running minimum, :func:`max` for a running maximum, or
139139
:func:`operator.mul` for a running product. Amortization tables can be
140140
built by accumulating interest and applying payments:
@@ -181,21 +181,14 @@ loops that truncate the stream.
181181
>>> unflattened
182182
[('roses', 'red'), ('violets', 'blue'), ('sugar', 'sweet')]
183183

184-
>>> for batch in batched('ABCDEFG', 3):
185-
... print(batch)
186-
...
187-
('A', 'B', 'C')
188-
('D', 'E', 'F')
189-
('G',)
190-
191184
Roughly equivalent to::
192185

193186
def batched(iterable, n):
194187
# batched('ABCDEFG', 3) → ABC DEF G
195188
if n < 1:
196189
raise ValueError('n must be at least one')
197-
it = iter(iterable)
198-
while batch := tuple(islice(it, n)):
190+
iterable = iter(iterable)
191+
while batch := tuple(islice(iterable, n)):
199192
yield batch
200193

201194
.. versionadded:: 3.12
@@ -229,13 +222,13 @@ loops that truncate the stream.
229222

230223
Return *r* length subsequences of elements from the input *iterable*.
231224

232-
The combination tuples are emitted in lexicographic ordering according to
225+
The combination tuples are emitted in lexicographic order according to
233226
the order of the input *iterable*. So, if the input *iterable* is sorted,
234227
the output tuples will be produced in sorted order.
235228

236229
Elements are treated as unique based on their position, not on their
237-
value. So if the input elements are unique, there will be no repeated
238-
values in each combination.
230+
value. So, if the input elements are unique, there will be no repeated
231+
values within each combination.
239232

240233
Roughly equivalent to::
241234

@@ -278,12 +271,12 @@ loops that truncate the stream.
278271
Return *r* length subsequences of elements from the input *iterable*
279272
allowing individual elements to be repeated more than once.
280273

281-
The combination tuples are emitted in lexicographic ordering according to
274+
The combination tuples are emitted in lexicographic order according to
282275
the order of the input *iterable*. So, if the input *iterable* is sorted,
283276
the output tuples will be produced in sorted order.
284277

285278
Elements are treated as unique based on their position, not on their
286-
value. So if the input elements are unique, the generated combinations
279+
value. So, if the input elements are unique, the generated combinations
287280
will also be unique.
288281

289282
Roughly equivalent to::
@@ -324,13 +317,13 @@ loops that truncate the stream.
324317
.. function:: compress(data, selectors)
325318

326319
Make an iterator that filters elements from *data* returning only those that
327-
have a corresponding element in *selectors* that evaluates to ``True``.
328-
Stops when either the *data* or *selectors* iterables has been exhausted.
320+
have a corresponding element in *selectors* is true.
321+
Stops when either the *data* or *selectors* iterables have been exhausted.
329322
Roughly equivalent to::
330323

331324
def compress(data, selectors):
332325
# compress('ABCDEF', [1,0,1,0,1,1]) → A C E F
333-
return (d for d, s in zip(data, selectors) if s)
326+
return (datum for datum, selector in zip(data, selectors) if selector)
334327

335328
.. versionadded:: 3.1
336329

@@ -384,7 +377,7 @@ loops that truncate the stream.
384377
start-up time. Roughly equivalent to::
385378

386379
def dropwhile(predicate, iterable):
387-
# dropwhile(lambda x: x<5, [1,4,6,4,1]) → 6 4 1
380+
# dropwhile(lambda x: x<5, [1,4,6,3,8]) → 6 3 8
388381
iterable = iter(iterable)
389382
for x in iterable:
390383
if not predicate(x):
@@ -400,7 +393,7 @@ loops that truncate the stream.
400393
that are false. Roughly equivalent to::
401394

402395
def filterfalse(predicate, iterable):
403-
# filterfalse(lambda x: x%2, range(10)) → 0 2 4 6 8
396+
# filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8
404397
if predicate is None:
405398
predicate = bool
406399
for x in iterable:
@@ -436,36 +429,37 @@ loops that truncate the stream.
436429

437430
:func:`groupby` is roughly equivalent to::
438431

439-
class groupby:
432+
def groupby(iterable, key=None):
440433
# [k for k, g in groupby('AAAABBBCCDAABBB')] → A B C D A B
441434
# [list(g) for k, g in groupby('AAAABBBCCD')] → AAAA BBB CC D
442435

443-
def __init__(self, iterable, key=None):
444-
if key is None:
445-
key = lambda x: x
446-
self.keyfunc = key
447-
self.it = iter(iterable)
448-
self.tgtkey = self.currkey = self.currvalue = object()
449-
450-
def __iter__(self):
451-
return self
452-
453-
def __next__(self):
454-
self.id = object()
455-
while self.currkey == self.tgtkey:
456-
self.currvalue = next(self.it) # Exit on StopIteration
457-
self.currkey = self.keyfunc(self.currvalue)
458-
self.tgtkey = self.currkey
459-
return (self.currkey, self._grouper(self.tgtkey, self.id))
460-
461-
def _grouper(self, tgtkey, id):
462-
while self.id is id and self.currkey == tgtkey:
463-
yield self.currvalue
464-
try:
465-
self.currvalue = next(self.it)
466-
except StopIteration:
436+
keyfunc = (lambda x: x) if key is None else key
437+
iterator = iter(iterable)
438+
exhausted = False
439+
440+
def _grouper(target_key):
441+
nonlocal curr_value, curr_key, exhausted
442+
yield curr_value
443+
for curr_value in iterator:
444+
curr_key = keyfunc(curr_value)
445+
if curr_key != target_key:
467446
return
468-
self.currkey = self.keyfunc(self.currvalue)
447+
yield curr_value
448+
exhausted = True
449+
450+
try:
451+
curr_value = next(iterator)
452+
except StopIteration:
453+
return
454+
curr_key = keyfunc(curr_value)
455+
456+
while not exhausted:
457+
target_key = curr_key
458+
curr_group = _grouper(target_key)
459+
yield curr_key, curr_group
460+
if curr_key == target_key:
461+
for _ in curr_group:
462+
pass
469463

470464

471465
.. function:: islice(iterable, stop)
@@ -493,13 +487,15 @@ loops that truncate the stream.
493487
# islice('ABCDEFG', 2, 4) → C D
494488
# islice('ABCDEFG', 2, None) → C D E F G
495489
# islice('ABCDEFG', 0, None, 2) → A C E G
490+
496491
s = slice(*args)
497492
start = 0 if s.start is None else s.start
498493
stop = s.stop
499494
step = 1 if s.step is None else s.step
500495
if start < 0 or (stop is not None and stop < 0) or step <= 0:
501496
raise ValueError
502-
indices = count() if stop is None else range(max(stop, start))
497+
498+
indices = count() if stop is None else range(max(start, stop))
503499
next_i = start
504500
for i, element in zip(indices, iterable):
505501
if i == next_i:
@@ -541,22 +537,25 @@ loops that truncate the stream.
541537
the output tuples will be produced in sorted order.
542538

543539
Elements are treated as unique based on their position, not on their
544-
value. So if the input elements are unique, there will be no repeated
540+
value. So, if the input elements are unique, there will be no repeated
545541
values within a permutation.
546542

547543
Roughly equivalent to::
548544

549545
def permutations(iterable, r=None):
550546
# permutations('ABCD', 2) → AB AC AD BA BC BD CA CB CD DA DB DC
551547
# permutations(range(3)) → 012 021 102 120 201 210
548+
552549
pool = tuple(iterable)
553550
n = len(pool)
554551
r = n if r is None else r
555552
if r > n:
556553
return
554+
557555
indices = list(range(n))
558556
cycles = list(range(n, n-r, -1))
559557
yield tuple(pool[i] for i in indices[:r])
558+
560559
while n:
561560
for i in reversed(range(r)):
562561
cycles[i] -= 1
@@ -572,7 +571,7 @@ loops that truncate the stream.
572571
return
573572

574573
The code for :func:`permutations` can be also expressed as a subsequence of
575-
:func:`product`, filtered to exclude entries with repeated elements (those
574+
:func:`product` filtered to exclude entries with repeated elements (those
576575
from the same position in the input pool)::
577576

578577
def permutations(iterable, r=None):
@@ -666,17 +665,16 @@ loops that truncate the stream.
666665
predicate is true. Roughly equivalent to::
667666

668667
def takewhile(predicate, iterable):
669-
# takewhile(lambda x: x<5, [1,4,6,4,1]) → 1 4
668+
# takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4
670669
for x in iterable:
671-
if predicate(x):
672-
yield x
673-
else:
670+
if not predicate(x):
674671
break
672+
yield x
675673

676674
Note, the element that first fails the predicate condition is
677675
consumed from the input iterator and there is no way to access it.
678676
This could be an issue if an application wants to further consume the
679-
input iterator after takewhile has been run to exhaustion. To work
677+
input iterator after *takewhile* has been run to exhaustion. To work
680678
around this problem, consider using `more-iterools before_and_after()
681679
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_
682680
instead.
@@ -726,10 +724,12 @@ loops that truncate the stream.
726724

727725
def zip_longest(*iterables, fillvalue=None):
728726
# zip_longest('ABCD', 'xy', fillvalue='-') → Ax By C- D-
729-
iterators = [iter(it) for it in iterables]
727+
728+
iterators = list(map(iter, iterables))
730729
num_active = len(iterators)
731730
if not num_active:
732731
return
732+
733733
while True:
734734
values = []
735735
for i, iterator in enumerate(iterators):

0 commit comments

Comments
 (0)