使用以下代码:
A = [1, 2] B = [-2, -1] C = [-1, 2] D = [0, 2] ab = (a + b for a in A for b in B) cd = (c + d for c in C for d in D) abcd = (e_ab + e_cd for e_ab in ab for e_cd in cd)
该len(abcd)
预期是16
,但它实际上是4
.如果我使用列表理解,问题就会消失.这是为什么?
您只能乘坐发电机列车一次,到达目的地后,不再乘坐.在您的情况下,cd
生成器已耗尽,然后无法再次迭代.
list
另一方面,对象每次调用iter
它们时都会创建一个单独的迭代器对象(for
循环为您隐式执行):
print(iter([1, 2, 3])) #
并生产一个你可以使用的新鲜迭代器.这种情况发生的任何时间 iter
在其上被调用; 由于每次都会生成一个新对象,因此您可以多次浏览列表.多次游乐设施!
简而言之,如果您只是更改cd
为一个列表(通常,将多次迭代的对象):
ab = (a + b for a in A for b in B) cd = [c + d for c in C for d in D] # list-comp instead
它将通过cd
为每个元素创建新的迭代器对象来产生想要的结果ab
:
abcd = (e_ab + e_cd for e_ab in ab for e_cd in cd) print(len(list(abcd))) # 16
当然你也可以通过实现这个product
来自itertools
太多,但,这是超越了为什么发生这种情况的地步.
我想这是因为你只能迭代生成器一次.因此,在e_cd
第一次完成循环后,这将不会在外部循环的另一次迭代中产生任何内容.
当生成器没有其他值返回时,它会引发StopIteration
异常.这就是他们发出信号的信号.由于没有内置的方法来重置生成器,当您从生成器创建多级生成器时,它将在第一次遇到时停止,StopIteration
而不是像子列表对象那样导致子生成器循环.
itertools.product()
可以产生预期的结果(在这里 repl.it ):
import itertools A = [1, 2] B = [-2, -1] C = [-1, 2] D = [0, 2] ab = (a + b for a in A for b in B) cd = (c + d for c in C for d in D) abcd = (e_ab + e_cd for e_ab, e_cd in itertools.product(ab,cd))