8000 [3.12] gh-113479: Link to workaround for subtle issue with takewhile(… · python/cpython@1245949 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1245949

Browse files
[3.12] gh-113479: Link to workaround for subtle issue with takewhile() (gh-115890) (gh-115910)
1 parent f684e25 commit 1245949

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

Doc/library/itertools.rst

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,14 @@ loops that truncate the stream.
680680
else:
681681
break
682682

683+
Note, the element that first fails the predicate condition is
684+
consumed from the input iterator and there is no way to access it.
685+
This could be an issue if an application wants to further consume the
686+
input iterator after takewhile has been run to exhaustion. To work
687+
around this problem, consider using `more-iterools before_and_after()
688+
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_
689+
instead.
690+
683691

684692
.. function:: tee(iterable, n=2)
685693

@@ -996,32 +1004,6 @@ which incur interpreter overhead.
9961004
except exception:
9971005
pass
9981006

999-
def before_and_after(predicate, it):
1000-
""" Variant of takewhile() that allows complete
1001-
access to the remainder of the iterator.
1002-
1003-
>>> it = iter('ABCdEfGhI')
1004-
>>> all_upper, remainder = before_and_after(str.isupper, it)
1005-
>>> ''.join(all_upper)
1006-
'ABC'
1007-
>>> ''.join(remainder) # takewhile() would lose the 'd'
1008-
'dEfGhI'
1009-
1010-
Note that the true iterator must be fully consumed
1011-
before the remainder iterator can generate valid results.
1012-
"""
1013-
it = iter(it)
1014-
transition = []
1015-
1016-
def true_iterator():
1017-
for elem in it:
1018-
if predicate(elem):
1019-
yield elem
1020-
else:
1021-
transition.append(elem)
1022-
return
1023-
1024-
return true_iterator(), chain(transition, it)
10251007

10261008

10271009
The following recipes have a more mathematical flavor:
@@ -1531,13 +1513,6 @@ The following recipes have a more mathematical flavor:
15311513
>>> list(odds)
15321514
[1, 3, 5, 7, 9]
15331515

1534-
>>> it = iter('ABCdEfGhI')
1535-
>>> all_upper, remainder = before_and_after(str.isupper, it)
1536-
>>> ''.join(all_upper)
1537-
'ABC'
1538-
>>> ''.join(remainder)
1539-
'dEfGhI'
1540-
15411516
>>> list(subslices('ABCD'))
15421517
['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D']
15431518

@@ -1628,6 +1603,32 @@ The following recipes have a more mathematical flavor:
16281603
result.append(pool[-1-n])
16291604
return tuple(result)
16301605

1606+
def before_and_after(predicate, it):
1607+
""" Variant of takewhile() that allows complete
1608+
access to the remainder of the iterator.
1609+
1610+
>>> it = iter('ABCdEfGhI')
1611+
>>> all_upper, remainder = before_and_after(str.isupper, it)
1612+
>>> ''.join(all_upper)
1613+
'ABC'
1614+
>>> ''.join(remainder) # takewhile() would lose the 'd'
1615+
'dEfGhI'
1616+
1617+
Note that the true iterator must be fully consumed
1618+
before the remainder iterator can generate valid results.
1619+
"""
1620+
it = iter(it)
1621+
transition = []
1622+
1623+
def true_iterator():
1624+
for elem in it:
1625+
if predicate(elem):
1626+
yield elem
1627+
else:
1628+
transition.append(elem)
1629+
return
1630+
1631+
return true_iterator(), chain(transition, it)
16311632

16321633
.. doctest::
16331634
:hide:
@@ -1657,3 +1658,10 @@ The following recipes have a more mathematical flavor:
16571658
>>> combos = list(combinations(iterable, r))
16581659
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
16591660
True
1661+
1662+
>>> it = iter('ABCdEfGhI')
1663+
>>> all_upper, remainder = before_and_after(str.isupper, it)
1664+
>>> ''.join(all_upper)
1665+
'ABC'
1666+
>>> ''.join(remainder)
1667+
'dEfGhI'

0 commit comments

Comments
 (0)
0