我编写了一个名为size_subsets的函数,当传递城市(数字)列表时,该函数返回一定大小的所有子集。但是,使用izip()而不是两个for-yield块重新定义该函数将完全破坏行为。

下面的第二种方法使用izip()重述了第一种方法,但是由于某种原因,它在顶层不返回任何内容。谁能帮我找出原因吗?

打印语句显示,某些正确的子集(并非全部)确实在size_subsets_broken递归的最底层得到了屈服,但是由于某些原因,即使这些也没有达到顶层。

def size_subsets(cities, size, sofar):
    if not size:
        yield sofar
        return
    elif len(cities) < size:
        return
    else:
        curr_city = cities.pop()
        for a in size_subsets(cities[:], size - 1, sofar | {curr_city}):
            yield a
        for b in size_subsets(cities[:], size, sofar):
            yield b


def size_subsets_broken(cities, size, sofar):
    if not size:
        yield sofar
        return
    elif len(cities) < size:
        return
    else:
        curr_city = cities.pop()
        inclusive = size_subsets_broken(cities[:], size - 1, sofar | {curr_city})
        exclusive = size_subsets_broken(cities[:], size, sofar)

        for incl_subset, excl_subset in izip(inclusive, exclusive):
            yield incl_subset
            yield excl_subset


print list(size_subsets([1, 2, 3], 2, set()))           # [set([2, 3]), set([1, 3]), set([1, 2])]
print list(size_subsets_broken([1, 2, 3], 2, set()))    # []

最佳答案

我怀疑您误解了izip()的工作原理。当最短的输入可迭代数用尽时,它就停止了,并且没有理由相信您的inclusiveexclusive始终具有相同的长度。

>>> from itertools import izip
>>> for i in izip(range(10), [6]):
...     print i
(0, 6)

>>> for i in izip(range(10), []):
...     print i


请注意,在第一个示例中只有一个输出,而在第二个示例中根本没有任何输出。这是所有的预期。

细节

size_subsets_broken()的顶级调用将创建一个生成器迭代器(gi)对象。对list()的调用强制后者执行某些操作。

它创建带有参数(忽略inclusiveexclusivegisofar[1, 2], 1 [1, 2], 2对象。然后izip()尝试将它们合并。

izip()首先尝试从inclusive获取一个值(最终无法提供任何东西,这就是为什么顶级gi也不产生任何东西的原因-实际上,它甚至从未尝试强迫exclusive产生任何东西,因为inclusive为空-izip()“当最短的输入iter用尽时,普通停止”)。

回想一下,顶级inclusive的参数是[1, 2], 1。它为gi[1], 0创建[1], 1对象。它的izip()推动[1], 0分支以通过if not size测试产生一个值。因此,其izip()继续将[1], 1分支推入一个值。

依次创建[], 0[], 1 gi分支。 izip()的另一层将其中的第一层推入一个值(再次通过if not size测试),但是由于if len(cities) < size: return,第二层分支不产生任何值。因此,上一级的izip()放弃,它所属的gi没有任何结果。

它沿链传播:在每个级别,izip()至少找到一个空的迭代器,因此从不输入for ... in izip(...):循环的主体(在任何级别)。

顺便说一句,这不是izip()的问题。尝试在此算法中使用izip()根本没有意义。

关于python - 使用izip的Python递归生成器中的意外行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37369923/

10-12 17:00