我有一个由多重yield返回的生成器对象。准备调用这个生成器是相当耗时的操作。这就是为什么我想重复使用发电机几次。
y = FunctionWithYield()
for x in y: print(x)
#here must be something to reset 'y'
for x in y: print(x)
当然,我正在考虑将内容复制到简单的列表中。有办法重置我的发电机吗?
请参见:如何提前查看Python生成器中的一个元素?
我有一个由多重yield返回的生成器对象。准备调用这个生成器是相当耗时的操作。这就是为什么我想重复使用发电机几次。
y = FunctionWithYield()
for x in y: print(x)
#here must be something to reset 'y'
for x in y: print(x)
当然,我正在考虑将内容复制到简单的列表中。有办法重置我的发电机吗?
请参见:如何提前查看Python生成器中的一个元素?
当前回答
可能最简单的解决方案是将昂贵的部分包装在一个对象中,并将其传递给生成器:
data = ExpensiveSetup()
for x in FunctionWithYield(data): pass
for x in FunctionWithYield(data): pass
这样,就可以缓存昂贵的计算。
如果您可以同时将所有结果保存在RAM中,那么可以使用list()将生成器的结果物化到一个普通列表中并使用该列表。
其他回答
现在可以使用more_itertools。Seekable(第三方工具),允许重置迭代器。
通过> pip Install more_itertools安装
import more_itertools as mit
y = mit.seekable(FunctionWithYield())
for x in y:
print(x)
y.seek(0) # reset iterator
for x in y:
print(x)
注意:内存消耗会随着迭代器的增加而增加,所以要警惕大型迭代对象。
>>> def gen():
... def init():
... return 0
... i = init()
... while True:
... val = (yield i)
... if val=='restart':
... i = init()
... else:
... i += 1
>>> g = gen()
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
>>> g.send('restart')
0
>>> g.next()
1
>>> g.next()
2
我想为一个老问题提供一个不同的解决方案
class IterableAdapter:
def __init__(self, iterator_factory):
self.iterator_factory = iterator_factory
def __iter__(self):
return self.iterator_factory()
squares = IterableAdapter(lambda: (x * x for x in range(5)))
for x in squares: print(x)
for x in squares: print(x)
与list(iterator)相比,这样做的好处是它的空间复杂度是O(1),而list(iterator)是O(n)。缺点是,如果你只能访问迭代器,而不能访问产生迭代器的函数,那么你就不能使用这个方法。例如,这样做似乎是合理的,但它不会起作用。
g = (x * x for x in range(5))
squares = IterableAdapter(lambda: g)
for x in squares: print(x)
for x in squares: print(x)
如果希望使用预定义的参数集多次重用此生成器,可以使用functools.partial。
from functools import partial
func_with_yield = partial(FunctionWithYield, arg0, arg1)
for i in range(100):
for x in func_with_yield():
print(x)
这将把生成器函数包装到另一个函数中,因此每次调用func_with_yield()时,它都会创建相同的生成器函数。
可能最简单的解决方案是将昂贵的部分包装在一个对象中,并将其传递给生成器:
data = ExpensiveSetup()
for x in FunctionWithYield(data): pass
for x in FunctionWithYield(data): pass
这样,就可以缓存昂贵的计算。
如果您可以同时将所有结果保存在RAM中,那么可以使用list()将生成器的结果物化到一个普通列表中并使用该列表。