]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] Misc improvements to the itertools docs (gh-119040) (#119044)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 14 May 2024 15:27:03 +0000 (17:27 +0200)
committerGitHub <noreply@github.com>
Tue, 14 May 2024 15:27:03 +0000 (15:27 +0000)
Doc/library/itertools.rst

index fdcf1f8d1e353ec2111283e3d25a000e41f523e2..183aa36d927550679c91901e9f3c473c6a255a05 100644 (file)
@@ -122,15 +122,15 @@ loops that truncate the stream.
             # accumulate([1,2,3,4,5]) → 1 3 6 10 15
             # accumulate([1,2,3,4,5], initial=100) → 100 101 103 106 110 115
             # accumulate([1,2,3,4,5], operator.mul) → 1 2 6 24 120
-            it = iter(iterable)
+            iterator = iter(iterable)
             total = initial
             if initial is None:
                 try:
-                    total = next(it)
+                    total = next(iterator)
                 except StopIteration:
                     return
             yield total
-            for element in it:
+            for element in iterator:
                 total = func(total, element)
                 yield total
 
@@ -210,9 +210,8 @@ loops that truncate the stream.
 
       def chain(*iterables):
           # chain('ABC', 'DEF') → A B C D E F
-          for it in iterables:
-              for element in it:
-                  yield element
+          for iterable in iterables:
+              yield from iterable
 
 
 .. classmethod:: chain.from_iterable(iterable)
@@ -222,9 +221,8 @@ loops that truncate the stream.
 
       def from_iterable(iterables):
           # chain.from_iterable(['ABC', 'DEF']) → A B C D E F
-          for it in iterables:
-              for element in it:
-                  yield element
+          for iterable in iterables:
+              yield from iterable
 
 
 .. function:: combinations(iterable, r)
@@ -688,24 +686,22 @@ loops that truncate the stream.
 
    Return *n* independent iterators from a single iterable.
 
-   The following Python code helps explain what *tee* does (although the actual
-   implementation is more complex and uses only a single underlying
-   :abbr:`FIFO (first-in, first-out)` queue)::
+   Roughly equivalent to::
 
         def tee(iterable, n=2):
-            it = iter(iterable)
-            deques = [collections.deque() for i in range(n)]
-            def gen(mydeque):
-                while True:
-                    if not mydeque:             # when the local deque is empty
-                        try:
-                            newval = next(it)   # fetch a new value and
-                        except StopIteration:
-                            return
-                        for d in deques:        # load it to all the deques
-                            d.append(newval)
-                    yield mydeque.popleft()
-            return tuple(gen(d) for d in deques)
+            iterator = iter(iterable)
+            empty_link = [None, None]  # Singly linked list: [value, link]
+            return tuple(_tee(iterator, empty_link) for _ in range(n))
+
+        def _tee(iterator, link):
+            while True:
+                if link[1] is None:
+                    try:
+                        link[:] = [next(iterator), [None, None]]
+                    except StopIteration:
+                        return
+                value, link = link
+                yield value
 
    Once a :func:`tee` has been created, the original *iterable* should not be
    used anywhere else; otherwise, the *iterable* could get advanced without
@@ -735,9 +731,9 @@ loops that truncate the stream.
               return
           while True:
               values = []
-              for i, it in enumerate(iterators):
+              for i, iterator in enumerate(iterators):
                   try:
-                      value = next(it)
+                      value = next(iterator)
                   except StopIteration:
                       num_active -= 1
                       if not num_active:
@@ -792,6 +788,7 @@ and :term:`generators <generator>` which incur interpreter overhead.
 .. testcode::
 
    import collections
+   import contextlib
    import functools
    import math
    import operator
@@ -934,32 +931,26 @@ and :term:`generators <generator>` which incur interpreter overhead.
        # iter_index('AABCADEAF', 'A') → 0 1 4 7
        seq_index = getattr(iterable, 'index', None)
        if seq_index is None:
-           # Path for general iterables
            iterator = islice(iterable, start, stop)
            for i, element in enumerate(iterator, start):
                if element is value or element == value:
                    yield i
        else:
-           # Path for sequences with an index() method
            stop = len(iterable) if stop is None else stop
            i = start
-           try:
+           with contextlib.suppress(ValueError):
                while True:
                    yield (i := seq_index(value, i, stop))
                    i += 1
-           except ValueError:
-               pass
 
    def iter_except(func, exception, first=None):
        "Convert a call-until-exception interface to an iterator interface."
        # iter_except(d.popitem, KeyError) → non-blocking dictionary iterator
-       try:
+       with contextlib.suppress(exception):
            if first is not None:
                yield first()
            while True:
                yield func()
-       except exception:
-           pass
 
 
 The following recipes have a more mathematical flavor: