summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2024-02-25 12:32:14 (GMT)
committerGitHub <noreply@github.com>2024-02-25 12:32:14 (GMT)
commita0a8d9ffe0ddb0f55aeb02801f48e722c2660ed3 (patch)
tree5fbcec85ca0c804f98897c881a4c144f88b2be6d
parentcb287d342139509e03a2dbe5ea2608627fd3a350 (diff)
downloadcpython-a0a8d9ffe0ddb0f55aeb02801f48e722c2660ed3.zip
cpython-a0a8d9ffe0ddb0f55aeb02801f48e722c2660ed3.tar.gz
cpython-a0a8d9ffe0ddb0f55aeb02801f48e722c2660ed3.tar.bz2
gh-113479: Link to workaround for subtle issue with takewhile() (gh-115890)
-rw-r--r--Doc/library/itertools.rst74
1 files changed, 41 insertions, 33 deletions
diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst
index 338a5f9..42e7040 100644
--- a/Doc/library/itertools.rst
+++ b/Doc/library/itertools.rst
@@ -688,6 +688,14 @@ loops that truncate the stream.
else:
break
+ Note, the element that first fails the predicate condition is
+ consumed from the input iterator and there is no way to access it.
+ This could be an issue if an application wants to further consume the
+ input iterator after takewhile has been run to exhaustion. To work
+ around this problem, consider using `more-iterools before_and_after()
+ <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_
+ instead.
+
.. function:: tee(iterable, n=2)
@@ -1004,32 +1012,6 @@ which incur interpreter overhead.
except exception:
pass
- def before_and_after(predicate, it):
- """ Variant of takewhile() that allows complete
- access to the remainder of the iterator.
-
- >>> it = iter('ABCdEfGhI')
- >>> all_upper, remainder = before_and_after(str.isupper, it)
- >>> ''.join(all_upper)
- 'ABC'
- >>> ''.join(remainder) # takewhile() would lose the 'd'
- 'dEfGhI'
-
- Note that the true iterator must be fully consumed
- before the remainder iterator can generate valid results.
- """
- it = iter(it)
- transition = []
-
- def true_iterator():
- for elem in it:
- if predicate(elem):
- yield elem
- else:
- transition.append(elem)
- return
-
- return true_iterator(), chain(transition, it)
The following recipes have a more mathematical flavor:
@@ -1543,13 +1525,6 @@ The following recipes have a more mathematical flavor:
>>> list(odds)
[1, 3, 5, 7, 9]
- >>> it = iter('ABCdEfGhI')
- >>> all_upper, remainder = before_and_after(str.isupper, it)
- >>> ''.join(all_upper)
- 'ABC'
- >>> ''.join(remainder)
- 'dEfGhI'
-
>>> list(subslices('ABCD'))
['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D']
@@ -1640,6 +1615,32 @@ The following recipes have a more mathematical flavor:
result.append(pool[-1-n])
return tuple(result)
+ def before_and_after(predicate, it):
+ """ Variant of takewhile() that allows complete
+ access to the remainder of the iterator.
+
+ >>> it = iter('ABCdEfGhI')
+ >>> all_upper, remainder = before_and_after(str.isupper, it)
+ >>> ''.join(all_upper)
+ 'ABC'
+ >>> ''.join(remainder) # takewhile() would lose the 'd'
+ 'dEfGhI'
+
+ Note that the true iterator must be fully consumed
+ before the remainder iterator can generate valid results.
+ """
+ it = iter(it)
+ transition = []
+
+ def true_iterator():
+ for elem in it:
+ if predicate(elem):
+ yield elem
+ else:
+ transition.append(elem)
+ return
+
+ return true_iterator(), chain(transition, it)
.. doctest::
:hide:
@@ -1669,3 +1670,10 @@ The following recipes have a more mathematical flavor:
>>> combos = list(combinations(iterable, r))
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
True
+
+ >>> it = iter('ABCdEfGhI')
+ >>> all_upper, remainder = before_and_after(str.isupper, it)
+ >>> ''.join(all_upper)
+ 'ABC'
+ >>> ''.join(remainder)
+ 'dEfGhI'