我无法想象我是第一个写这样一个类的人:
class RestartableGenerator:
def __init__(self, g):
self.g = g
def __iter__(self):
return self.g().__iter__()
if __name__=='__main__':
def gen():
print 'Generating'
for i in range(5):
yield i
i = RestartableGenerator(gen)
print 'Using'
print list(i)
print list(i)
测试产生此输出:
Using
Generating
[0, 1, 2, 3, 4]
Generating
[0, 1, 2, 3, 4]
但我没有在标准库中找到它。我查看了itertools和functools。
真的不存在吗?如果是,在哪里?
是否认为没有必要,因为当您想多次评估序列时,最好将其存储在列表中?
编辑1: 我的用例是我希望它对于消费者是透明的,出于内存消耗的原因,序列是生成器而不是列表。
编辑2:如果标准库中没有这样的类,您认为哪个名称合适? ParenthesisRemover? MultipleTimesIterable?还要别的吗?为什么呢?
答案 0 :(得分:2)
你可以稍微简化一下:
class RestartableGenerator:
def __init__(self, g):
self.g = g
def __iter__(self):
return self.g()
调用gen()
会返回一个生成器对象。生成器对象有一个next
方法,这是__iter__
必须返回的对象类型。
然而,不需要RestartableGenerator
,因为gen
本身无法做任何事情。不要将gen
保留在类属性中,只需抓住gen
本身。
def gen():
print 'Generating'
for i in range(5):
yield i
print 'Using'
print list(gen())
print list(gen())
答案 1 :(得分:2)
在返回到序列的开头的意义上,这不是完全可重新启动的。每个__iter__
调用都会创建一个新的生成器,它将重新运行生成器代码,可能会重新执行副作用并产生不同的结果。如果您想在生成的序列上使用独立的迭代器,那就是list
或itertools.tee
的用途。否则,再次明确调用生成器函数会更清楚,因此这不是很有用。您可以以不太明确,更容易出错的代码为代价来保存一对括号。
注意,如果你想要一个惰性序列类型,迭代它会动态生成元素,但你可以重复迭代它,你应该将它的__iter__
方法定义为生成器:
class Primes(object):
def __iter__(self):
for i in itertools.count():
if is_prime(i):
yield i
这不是“可重启的发电机”,但听起来就像你想要的那样。