繁体   English   中英

如何立即运行生成器函数的初始化代码,而不是在第一次调用时?

[英]How can I run the initialization code for a generator function immediately, rather than at the first call?

我有一个生成器函数,它是这样的:

def mygenerator():
    next_value = compute_first_value() # Costly operation
    while next_value != terminating_value:
        yield next_value
        next_value = compute_next_value()

我希望在调用函数后立即运行初始化步骤(在 while 循环之前),而不是仅在第一次使用生成器时运行。 有什么好方法可以做到这一点?

我想这样做是因为生成器将在单独的线程(或进程,或任何多处理使用)中运行,并且我不会在短时间内使用返回,并且初始化有点昂贵,所以我想要它在我准备使用这些值时进行初始化。

我需要类似的东西。 这就是我登陆的地方。 将生成器函数推入内部并返回它的调用。

def mygenerator():
    next_value = compute_first_value()

    def generator():
        while next_value != terminating_value:
            yield next_value
            next_value = compute_next(next_value)

    return generator()
class mygenerator(object):
    def __init__(self):
        self.next_value = self.compute_first_value()
    def __iter__(self):
        return self
    def next(self):
        if self.next_value == self.terminating_value:
            raise StopIteration()
        return self.next_value

您可以使用itertools.chain相当容易地创建一个“预先准备好的”迭代器:

from itertools import chain

def primed(iterable):
    """Preprimes an iterator so the first value is calculated immediately
       but not returned until the first iteration
    """
    itr = iter(iterable)
    try:
        first = next(itr)  # itr.next() in Python 2
    except StopIteration:
        return itr
    return chain([first], itr)

>>> def g():
...     for i in range(5):
...         print("Next called")
...         yield i
...
>>> x = primed(g())
Next called
>>> for i in x: print(i)
...
0
Next called
1
Next called
2
Next called
3
Next called
4

我想你可以在第一条语句完成后产生 None ,然后在你的调用代码中:

gen = mygenerator()
next(gen) # toss the None
do_something(gen)

对于我的用例,我使用了@ncoghlan 答案的修改版本,但包装在工厂函数中来装饰生成函数:

import collections, functools, itertools

def primed_generator(generating_function):
    @functools.wraps(generating_function)
    def get_first_right_away_wrapper(*args,**kw):
        "call the generator function, prime before returning"
        gen = generating_function(*args,**kw)
        assert isinstance(gen,collections.Iterator)
        first_value = next(gen)
        return itertools.chain((first_value,),gen)
    return get_first_right_away_wrapper

然后只是装饰功能:

@primed_generator
def mygenerator():
    next_value = compute_first_value() # Costly operation
    while next_value != terminating_value:
        yield next_value
        next_value = compute_next_value()

并且会立即计算第一个值,结果是透明的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM