两个功能,一个发电机

时间:2016-02-14 18:25:33

标签: python

我有两个函数,它们都将迭代器作为输入。有没有办法编写一个我可以作为输入提供给两个函数的生成器,这不需要reset或第二次通过?我想对数据进行一次传递,但是将输出提供给两个函数:示例:

def my_generator(data):
    for row in data:
        yield row

gen = my_generator(data)
func1(gen)
func2(gen)

我知道我可以有两个不同的生成器实例,或者在函数之间有reset,但是想知道是否有办法避免对数据进行两次传递。请注意,func1 / func2本身不是生成器,这很好,因为我可以有一个管道。

这里的要点是尽量避免对数据进行第二次传递。

3 个答案:

答案 0 :(得分:3)

Python有一个非常方便的功能目录。您可以在itertools中找到与迭代器相关的内容:

import itertools

def my_generator(data):
    for row in data:
        yield row

gen = my_generator(data)
gen1, gen2 = itertools.tee(gen)
func1(gen1)
func2(gen2)

但是,只有func1func2不消耗所有元素才有意义,因为itertools.tee()必须记住gen中的所有元素直到使用gen2

要解决此问题,请一次只使用几个元素。或者更改func1以致电func2。或者甚至可以将func1更改为一个惰性生成器,它返回输入并将其输入func2

答案 1 :(得分:3)

您可以缓存生成器结果列表, 重置生成器,以将数据传递到class Test { public static void main(String[] args) { double result = Math.pow(4 , 2); System.out.println(result); } } 。问题是,如果一个有2个循环,则需要迭代数据两次,因此要么再次加载数据并创建生成器,要么缓存整个结果。

func2这样的解决方案也只会创建2个迭代,这与在第一次迭代后重置生成器基本相同。当然它是语法糖,但它不会改变后台的情况。

如果此处有大数据,则必须合并itertools.teefunc1

func2

在实践中,设计这样的代码是一个好主意,因此可以完全控制迭代过程,并且可以使用单个迭代关联/组合映射和过滤器。

答案 2 :(得分:3)

如果使用线程是一个选项,则生成器可以只消耗一次,而不必在对消费者的调用之间存储可能不可预测的数量的产生值。以下示例以锁定步骤运行使用者;此实现需要Python 3.2或更高版本:

import threading


def generator():
    for x in range(10):
        print('generating {}'.format(x))
        yield x


def tee(iterable, n=2):
    barrier = threading.Barrier(n)
    state = dict(value=None, stop_iteration=False)

    def repeat():
        while True:
            if barrier.wait() == 0:
                try:
                    state.update(value=next(iterable))
                except StopIteration:
                    state.update(stop_iteration=True)
            barrier.wait()
            if state['stop_iteration']:
                break
            yield state['value']

    return tuple(repeat() for i in range(n))


def func1(iterable):
    for x in iterable:
        print('func1 consuming {}'.format(x))


def func2(iterable):
    for x in iterable:
        print('func2 consuming {}'.format(x))


gen1, gen2 = tee(generator(), 2)

thread1 = threading.Thread(target=func1, args=(gen1,))
thread1.start()

thread2 = threading.Thread(target=func2, args=(gen2,))
thread2.start()

thread1.join()
thread2.join()
相关问题