Python标准库中可用的可重启生成器?

时间:2013-08-22 20:48:27

标签: python

我无法想象我是第一个写这样一个类的人:

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?还要别的吗?为什么呢?

2 个答案:

答案 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__调用都会创建一个新的生成器,它将重新运行生成器代码,可能会重新执行副作用并产生不同的结果。如果您想在生成的序列上使用独立的迭代器,那就是listitertools.tee的用途。否则,再次明确调用生成器函数会更清楚,因此这不是很有用。您可以以不太明确,更容易出错的代码为代价来保存一对括号。

注意,如果你想要一个惰性序列类型,迭代它会动态生成元素,但你可以重复迭代它,你应该将它的__iter__方法定义为生成器:

class Primes(object):
    def __iter__(self):
        for i in itertools.count():
            if is_prime(i):
                yield i

这不是“可重启的发电机”,但听起来就像你想要的那样。