2011-04-19 41 views
8

我有一个是这样的发电机功能:如何立即运行生成器函数的初始化代码,而不是在第一次调用?

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

我想初始化步骤(while循环之前)尽快函数被调用运行,而不是只当发电机是第一用过的。什么是这样做的好方法?

我想这样做,因为生成器将运行在一个单独的线程(或进程,或任何多处理使用),我将不会使用返回一会儿,初始化有点昂贵,所以我希望它在我准备好使用这些值时进行初始化。

回答

13
class mygenerator(object): 
    def __init__(self): 
     next_value = compute_first_value() 
    def __iter__(self): 
     return self 
    def next(self): 
     if next_value == terminating_value: 
      raise StopIteration() 
     return next_value 
+1

这是“正确”的方法。其他人都是黑客。他们创作和使用可能很有趣,写得比较短,但难以阅读和介意难以维系。 – jsbueno 2011-04-20 03:54:01

6

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

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

您可以创建一个“preprimed”迭代器很容易通过使用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 
6

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

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() 
0

对于我的使用情况下,我使用的@ncoghlan answer修改后的版本,但包裹在一个工厂函数来装点生成函数:

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() 

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

相关问题