Skip to content

Commit 154e7fb

Browse files
committed
Misc improvement to the docs for itertools (pythongh-119529)
1 parent 392a3d8 commit 154e7fb

File tree

1 file changed

+55
-55
lines changed

1 file changed

+55
-55
lines changed

Diff for: Doc/library/itertools.rst

+55-55
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:
@@ -184,21 +184,14 @@ loops that truncate the stream.
184184
>>> unflattened
185185
[('roses', 'red'), ('violets', 'blue'), ('sugar', 'sweet')]
186186

187-
>>> for batch in batched('ABCDEFG', 3):
188-
... print(batch)
189-
...
190-
('A', 'B', 'C')
191-
('D', 'E', 'F')
192-
('G',)
193-
194187
Roughly equivalent to::
195188

196189
def batched(iterable, n, *, strict=False):
197190
# batched('ABCDEFG', 3) → ABC DEF G
198191
if n < 1:
199192
raise ValueError('n must be at least one')
200-
it = iter(iterable)
201-
while batch := tuple(islice(it, n)):
193+
iterable = iter(iterable)
194+
while batch := tuple(islice(iterable, n)):
202195
if strict and len(batch) != n:
203196
raise ValueError('batched(): incomplete batch')
204197
yield batch
@@ -237,13 +230,13 @@ loops that truncate the stream.
237230

238231
Return *r* length subsequences of elements from the input *iterable*.
239232

240-
The combination tuples are emitted in lexicographic ordering according to
233+
The combination tuples are emitted in lexicographic order according to
241234
the order of the input *iterable*. So, if the input *iterable* is sorted,
242235
the output tuples will be produced in sorted order.
243236

244237
Elements are treated as unique based on their position, not on their
245-
value. So if the input elements are unique, there will be no repeated
246-
values in each combination.
238+
value. So, if the input elements are unique, there will be no repeated
239+
values within each combination.
247240

248241
Roughly equivalent to::
249242

@@ -286,12 +279,12 @@ loops that truncate the stream.
286279
Return *r* length subsequences of elements from the input *iterable*
287280
allowing individual elements to be repeated more than once.
288281

289-
The combination tuples are emitted in lexicographic ordering according to
282+
The combination tuples are emitted in lexicographic order according to
290283
the order of the input *iterable*. So, if the input *iterable* is sorted,
291284
the output tuples will be produced in sorted order.
292285

293286
Elements are treated as unique based on their position, not on their
294-
value. So if the input elements are unique, the generated combinations
287+
value. So, if the input elements are unique, the generated combinations
295288
will also be unique.
296289

297290
Roughly equivalent to::
@@ -332,13 +325,13 @@ loops that truncate the stream.
332325
.. function:: compress(data, selectors)
333326

334327
Make an iterator that filters elements from *data* returning only those that
335-
have a corresponding element in *selectors* that evaluates to ``True``.
336-
Stops when either the *data* or *selectors* iterables has been exhausted.
328+
have a corresponding element in *selectors* is true.
329+
Stops when either the *data* or *selectors* iterables have been exhausted.
337330
Roughly equivalent to::
338331

339332
def compress(data, selectors):
340333
# compress('ABCDEF', [1,0,1,0,1,1]) → A C E F
341-
return (d for d, s in zip(data, selectors) if s)
334+
return (datum for datum, selector in zip(data, selectors) if selector)
342335

343336
.. versionadded:: 3.1
344337

@@ -392,7 +385,7 @@ loops that truncate the stream.
392385
start-up time. Roughly equivalent to::
393386

394387
def dropwhile(predicate, iterable):
395-
# dropwhile(lambda x: x<5, [1,4,6,4,1]) → 6 4 1
388+
# dropwhile(lambda x: x<5, [1,4,6,3,8]) → 6 3 8
396389
iterable = iter(iterable)
397390
for x in iterable:
398391
if not predicate(x):
@@ -408,7 +401,7 @@ loops that truncate the stream.
408401
that are false. Roughly equivalent to::
409402

410403
def filterfalse(predicate, iterable):
411-
# filterfalse(lambda x: x%2, range(10)) → 0 2 4 6 8
404+
# filterfalse(lambda x: x<5, [1,4,6,3,8]) → 6 8
412405
if predicate is None:
413406
predicate = bool
414407
for x in iterable:
@@ -444,36 +437,37 @@ loops that truncate the stream.
444437

445438
:func:`groupby` is roughly equivalent to::
446439

447-
class groupby:
440+
def groupby(iterable, key=None):
448441
# [k for k, g in groupby('AAAABBBCCDAABBB')] → A B C D A B
449442
# [list(g) for k, g in groupby('AAAABBBCCD')] → AAAA BBB CC D
450443

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

478472

479473
.. function:: islice(iterable, stop)
@@ -501,13 +495,15 @@ loops that truncate the stream.
501495
# islice('ABCDEFG', 2, 4) → C D
502496
# islice('ABCDEFG', 2, None) → C D E F G
503497
# islice('ABCDEFG', 0, None, 2) → A C E G
498+
504499
s = slice(*args)
505500
start = 0 if s.start is None else s.start
506501
stop = s.stop
507502
step = 1 if s.step is None else s.step
508503
if start < 0 or (stop is not None and stop < 0) or step <= 0:
509504
raise ValueError
510-
indices = count() if stop is None else range(max(stop, start))
505+
506+
indices = count() if stop is None else range(max(start, stop))
511507
next_i = start
512508
for i, element in zip(indices, iterable):
513509
if i == next_i:
@@ -549,22 +545,25 @@ loops that truncate the stream.
549545
the output tuples will be produced in sorted order.
550546

551547
Elements are treated as unique based on their position, not on their
552-
value. So if the input elements are unique, there will be no repeated
548+
value. So, if the input elements are unique, there will be no repeated
553549
values within a permutation.
554550

555551
Roughly equivalent to::
556552

557553
def permutations(iterable, r=None):
558554
# permutations('ABCD', 2) → AB AC AD BA BC BD CA CB CD DA DB DC
559555
# permutations(range(3)) → 012 021 102 120 201 210
556+
560557
pool = tuple(iterable)
561558
n = len(pool)
562559
r = n if r is None else r
563560
if r > n:
564561
return
562+
565563
indices = list(range(n))
566564
cycles = list(range(n, n-r, -1))
567565
yield tuple(pool[i] for i in indices[:r])
566+
568567
while n:
569568
for i in reversed(range(r)):
570569
cycles[i] -= 1
@@ -580,7 +579,7 @@ loops that truncate the stream.
580579
return
581580

582581
The code for :func:`permutations` can be also expressed as a subsequence of
583-
:func:`product`, filtered to exclude entries with repeated elements (those
582+
:func:`product` filtered to exclude entries with repeated elements (those
584583
from the same position in the input pool)::
585584

586585
def permutations(iterable, r=None):
@@ -674,17 +673,16 @@ loops that truncate the stream.
674673
predicate is true. Roughly equivalent to::
675674

676675
def takewhile(predicate, iterable):
677-
# takewhile(lambda x: x<5, [1,4,6,4,1]) → 1 4
676+
# takewhile(lambda x: x<5, [1,4,6,3,8]) → 1 4
678677
for x in iterable:
679-
if predicate(x):
680-
yield x
681-
else:
678+
if not predicate(x):
682679
break
680+
yield x
683681

684682
Note, the element that first fails the predicate condition is
685683
consumed from the input iterator and there is no way to access it.
686684
This could be an issue if an application wants to further consume the
687-
input iterator after takewhile has been run to exhaustion. To work
685+
input iterator after *takewhile* has been run to exhaustion. To work
688686
around this problem, consider using `more-iterools before_and_after()
689687
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_
690688
instead.
@@ -734,10 +732,12 @@ loops that truncate the stream.
734732

735733
def zip_longest(*iterables, fillvalue=None):
736734
# zip_longest('ABCD', 'xy', fillvalue='-') → Ax By C- D-
737-
iterators = [iter(it) for it in iterables]
735+
736+
iterators = list(map(iter, iterables))
738737
num_active = len(iterators)
739738
if not num_active:
740739
return
740+
741741
while True:
742742
values = []
743743
for i, iterator in enumerate(iterators):

0 commit comments

Comments
 (0)