当前位置:  开发笔记 > 编程语言 > 正文

嵌套的生成器表达式意外地表现

如何解决《嵌套的生成器表达式意外地表现》经验,为你挑选了3个好方法。

使用以下代码:

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.如果我使用列表理解,问题就会消失.这是为什么?



1> Jim Fasaraki..:

您只能乘坐发电机列车一次,到达目的地后,不再乘坐.在您的情况下,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太多,但,这是超越了为什么发生这种情况的地步.



2> neverwalkalo..:

我想这是因为你只能迭代生成器一次.因此,在e_cd第一次完成循环后,这将不会在外部循环的另一次迭代中产生任何内容.



3> Ouroborus..:

当生成器没有其他值返回时,它会引发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))

推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有