Python专家提问:调用生成器时代码不起作用

3

我有一个小片段在某种不可思议的方式下无法正常工作。
其目的是生成两个或更多序列的所有组合。
当使用列表调用时,它可以工作,但是当使用生成器调用时却不能。

def comb(seqs):
    if seqs:
        for item in seqs[0]:
            for rest in comb(seqs[1:]):
                yield [item] + rest
    else:
        yield []

if __name__=="__main__":
    x=[1,2]
    y=[3,4]
    print list(comb([x,y])) # prints [[1, 3], [1, 4], [2, 3], [2, 4]]

    def gen1(): yield 1; yield 2
    def gen2(): yield 3; yield 4
    x=gen1()
    y=gen2()
    print list(comb([x,y])) # prints [[1, 3], [1, 4]  WHY ????

2
旁注:为什么你不使用 itertools.product - Björn Pollex
@Space_Cowboy:这是为了自己的学习。我想知道为什么它不起作用。 - Alain
4个回答

7

生成器在生成完其要生成的所有内容后就会耗尽,而列表可以被多次迭代。

你的comb生成器依赖于能够多次迭代传递给它的第二个及以后序列,因此如果这些序列实际上是生成器,则无法正常工作。


2
原因在于您只能对生成器进行一次迭代。在该行中:
for item in seqs[0]

当你到达gen1的第二个元素时,你会对gen2的元素进行递归调用。问题是,在之前的递归调用中,你已经迭代过gen2,因此它不会产生任何项。


我接受你的答案。Charles 也给了我正确的答案,但是你是第一个回答的,谢谢。 - Alain
@Alain:实际上,Charles 是第一个发表完整答案的。我先发布了一个简短的回答,然后才详细阐述。 - Björn Pollex

2

修复:

def comb(seqs):
    if seqs:
        inner = list(comb(seqs[1:]))        
        for item in seqs[0]:
            for rest in inner:
                yield [item] + rest
    else:
        yield []

0

请查看docs.python.org中的itertools,您可能会找到创建高效循环迭代器所需的一切。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接