From cf984cee934dd5375596ca980fee45e1d943b9ef Mon Sep 17 00:00:00 2001
From: Raymond Hettinger <python@rcn.com>
Date: Wed, 18 Feb 2009 20:56:51 +0000
Subject: [PATCH] Generalize the itertools.tee() recipe.

---
 Doc/library/itertools.rst | 48 +++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst
index 7fdadd2aa0a..491cb184a18 100644
--- a/Doc/library/itertools.rst
+++ b/Doc/library/itertools.rst
@@ -130,7 +130,7 @@ loops that truncate the stream.
                 return
             indices = list(range(r))
             yield tuple(pool[i] for i in indices)
-            while 1:
+            while True:
                 for i in reversed(range(r)):
                     if indices[i] != i + n - r:
                         break
@@ -178,7 +178,7 @@ loops that truncate the stream.
                 return
             indices = [0] * r
             yield tuple(pool[i] for i in indices)
-            while 1:
+            while True:
                 for i in reversed(range(r)):
                     if indices[i] != n - 1:
                         break
@@ -501,28 +501,28 @@ loops that truncate the stream.
 
 .. function:: tee(iterable[, n=2])
 
-   Return *n* independent iterators from a single iterable. The case where ``n==2``
-   is equivalent to::
-
-      def tee(iterable):
-          def gen(next, data={}):
-              for i in count():
-                  if i in data:
-                      yield data.pop(i)
-                  else:
-                      data[i] = next()
-                      yield data[i]
-          it = iter(iterable)
-          return (gen(it.__next__), gen(it.__next__))
-
-   Note, once :func:`tee` has made a split, the original *iterable* should not be
-   used anywhere else; otherwise, the *iterable* could get advanced without the tee
-   objects being informed.
-
-   Note, this member of the toolkit may require significant auxiliary storage
-   (depending on how much temporary data needs to be stored). In general, if one
-   iterator is going to use most or all of the data before the other iterator, it
-   is faster to use :func:`list` instead of :func:`tee`.
+   Return *n* independent iterators from a single iterable.  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
+                        newval = next(it)       # fetch a new value and
+                        for d in deques:        # load it to all the deques
+                            d.append(newval)
+                    yield mydeque.popleft()
+            return tuple(gen(d) for d in deques)
+
+   Once :func:`tee` has made a split, the original *iterable* should not be
+   used anywhere else; otherwise, the *iterable* could get advanced without
+   the tee objects being informed.
+
+   This itertool may require significant auxiliary storage (depending on how
+   much temporary data needs to be stored). In general, if one iterator uses
+   most or all of the data before another iterator starts, it is faster to use
+   :func:`list` instead of :func:`tee`.
 
 
 .. function:: zip_longest(*iterables[, fillvalue])
-- 
2.30.9