通过链式调用生成器函数以构建一个数据管道

通过链式调用生成器函数以构建一个数据管道

假设有一系列生成器函数,我们想链式调用它们构建一个数据管道,如下:

#!/usr/bin/python
import itertools

def foo1(g):
    for i in g:
        yield i + 1

def foo2(g):
    for i in g:
        yield 10 + i

def foo3(g):
    for i in g:
        yield 'foo3:' + str(i)

res = foo3(foo2(foo1(range(0, 5))))

for i in res:
    print i

输出:

foo3:11
foo3:12
foo3:13
foo3:14
foo3:15

foo3(foo2(foo1(range(0, 5)))) 不是一个比较 pythonic 的方式。特别是当管道需要处理的步骤变多时。

假如可以像下边这样调用的话,会好很多:

range(0, 5).foo1().foo2().foo3()

或者

l = [range(0, 5), foo1, foo2, foo3]
res = runner.run(l)

解决方案

from functools import reduce
def pipeline(*steps):
    return reduce(lambda x, y: y(x), list(steps))

res = pipeline(range(0, 5), foo1, foo2, foo3)

更好:

def compose(*funcs):
    return lambda x: reduce(lambda f, g: g(f), list(funcs), x)

p = compose(foo1, foo2, foo3)
res = p(range(0, 5))

参考

pythonic-way-to-chain-python-generator-function-to-form-a-pipeline

How to join two generators in Python?

updated_at 25-10-2019