[Python-ideas] pipe function for itertools?

Steven D'Aprano steve at pearwood.info
Tue May 26 18:46:16 CEST 2009


On Tue, 26 May 2009 08:32:58 pm Donald 'Paddy' McCarthy wrote:
> Hi, I have a blog entry,
> http://paddy3118.blogspot.com/2009/05/pipe-fitting-with-python-genera
>tors.html, in which I define a helper function to get around the
> problem of reversion in the nesting of generators and the
> proliferation of nested brackets.
>
> See the blog entry for a fuller treatment, but in essence if you have
> a series of generators, and want the data to conceptually flow like
> this:
>
> gen1 -> gen2 -> gen3 -> gen4 ...
>
> You have to write:
>
> ...(gen4(gen3(gen2(gen1()))))...
>
> With pipe, you would write:
>
> pipe(gen1, gen2, gen3, gen4, ...)
> 
> Which you could use like this:
>
> for data in pipe(...): do_something_with_data()
>
>
> If I use dots for indentation, then maybe the definition will come
> through to the group:
>
> def pipe(*cmds):
> ....gen = cmds[0]
> ....for cmd in cmds[1:]:
> ....... gen = cmd(gen)
> ....for x in gen:
> ....... yield x


The function signature is misleading. It doesn't take a series of 
generator functions ("cmds"), it takes an initial iterable followed by 
a series of generator functions.

It seems to me that a cleaner definition would be:

def pipe(iterable, *generators):
    for gen in generators:
        iterable = gen(iterable)
    for x in iterable:
        yield x


This does seem to be a special case of function composition. If 
functools grew a compose() function, you could write:

from functools import compose
def pipe(it, *gens):
    for x in compose(*gens)(it):
        yield x

Here's an untested definition for compose:

def compose(f, *funcs, **kwargs):
    if not funcs:
        raise TypeError('compose() requires at least two functions')
    if kwargs.keys() not in ([], ['doc']):
        # I wish Python 2.5 had keyword only args...
        raise TypeError('bad keyword argument(s)')
    def function_composition(*args, **kwargs):
        value = f(*args, **kwargs)
        for g in funcs:
            value = g(value)
        return value
    function_composition.__doc__ = kwargs.get('doc')
    return function_composition

which is more complicated than your version, of course, but also more 
general.



> A couple of readers thought that it might be a good tool for
> itertools to have.

Do you have any other use-cases?




-- 
Steven D'Aprano



More information about the Python-ideas mailing list