列出生成器和循环之间的区别

时间:2018-09-27 00:37:20

标签: python generator

看这个answer,似乎使用列表推导(或for的{​​{1}}循环)等效于在迭代器上调用append。由于也generators are iterators,我希望生成器也一样。但是,如果您运行

list(..)

It prints

def permute(xs, count, low = 0):
    if low + 1 >= count:
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p
        for i in range(low + 1, count):
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p
            xs[low], xs[i] = xs[i], xs[low]

print("Direct iteration")
for x in permute([1, 2], 2):
    print(x)
print("Listing")
for x in list(permute([1, 2], 2)):
  print(x)

为什么会这样?

1 个答案:

答案 0 :(得分:3)

您正在反复修改并产生相同的列表xs。生成器运行时,列表内容正在更改。看起来它起作用了,因为尽管每个print(x)都打印相同的列表对象,但是该对象每次都具有不同的内容。

另一方面,第二个循环使生成器运行到完成并收集所有列表引用。 然后它会打印出列表-除非它们都是相同的列表,所以每一行都是相同的!

将两行print(x)更改为print(x, id(x)),您将明白我的意思。 ID号将完全相同。

Direct iteration
[1, 2] 140685039497928
[2, 1] 140685039497928
Listing
[1, 2] 140685039497736
[1, 2] 140685039497736

一个快速的解决方法是产生列表的副本,而不是原始列表。 yield p很好,但是yield xs应该变成:

yield xs[:]

通过该修复,结果如预期的那样:

Direct iteration
[1, 2] 140449546108424
[2, 1] 140449546108744
Listing
[1, 2] 140449546108424
[2, 1] 140449546108808

两个循环的结果相同,并且ID号不同。