[Python-ideas] A cute Python implementation of itertools.tee

Tim Peters tim.peters at gmail.com
Mon May 7 20:33:47 EDT 2018


I posted this several weeks ago, just for fun - an obscure but
surprisingly brief Python implementation of itertools.tee, sharing a
single stream (as a singly linked list) among all the returned
iterables.

Didn't think about it again until today, when recent discussions of
lexical scoping made me wonder "hmm - when's the last time I even used
nonlocal?".  Well, this was.  And shortly thereafter, "but there's no
need to keep track of `last` at all!"  I have no idea where that
thought came from :-)

>     def mytee(xs, n):
>         last = [None, None]
>
>         def gen(it, mylast):
>             nonlocal last
>             while True:
>                 mylast = mylast[1]
>                 if not mylast:
>                     mylast = last[1] = last = [next(it), None]
>                 yield mylast[0]
>
>         it = iter(xs)
>         return tuple(gen(it, last) for _ in range(n))

So, in fact, the inner function there can be replaced by the even briefer:

        def gen(it, mylast):
            while True:
                if mylast[1] is None:
                    mylast[1] = [next(it), None]
                mylast = mylast[1]
                yield mylast[0]

To make it more relevant to current discussions, collapsing the last
two lines using a binding expression:

                yield (mylast := mylast[1])[0]

isn't even slightly tempting.  Most of the cases where it would be
_possible_ to use binding expressions don't strike me as being
_sensible_ places to use them - slamming together conceptually
different tasks just because it's possible to do so.  But because name
bindings are so very common, that still leaves plenty where the
transformation leaves the code clearer to my eyes (usually just a
little, rarely a lot).  There are no such cases in the code above.


More information about the Python-ideas mailing list