g=(i for i in range(4))
for i in [1,10]:
g=(i+j for j in g)
print(list(g))
请问为什么结果是:[20, 21, 22, 23]
而不是:[11,12,13,14] 呢?
g=(i for i in range(4))
for i in [1,10]:
g=(i+j for j in g)
print(list(g))
请问为什么结果是:[20, 21, 22, 23]
而不是:[11,12,13,14] 呢?
生成器的特点是并没有立即执行,而是记住'生产方式',等被调用时再执行.
在您的这个例子中:
g=(i for i in range(4))#此时,如果被list调用,g为会是[0,1,2,3],但没有被调用,只是生成器
以下循环中:
for i in [1,10]:
g=(i+j for j in g)
并不是说,第一次循环i为1时,g就应该为[1,2,3,4],其实g并没有被调用,所有并没有执行,只是记住生成器的值为i+j而已
第二循环时,i为10,同样也没有执行,也仅仅是记住i+j而已
当被print(list(g))命令调用执行时,循环中的变量i的值,已经是10了.
所以最终的g中的每一值,是执行连续执行两次i+j,既i+(i+j)
所以print(list(g))的输出是[20, 21, 22, 23]
还有更神奇的,同样是你的代码:
g=(i for i in range(4))
for i in [1,10]:
g=(i+j for j in g)
for i in g:
print(i)#输出会是20,41,84,171
输出结果和list(g)又不一样,是不是更奇怪?
但是如果改一下循环变量名称:
for k in g:
print(k)#输出20, 21, 22, 23
输出结果就和list(g)一致了.为什么了?
还是因为生产器的'记住生产方式,而没有被立即执行'的原因.
在生成器g中,变量i是一直存在,并没有被释放和回收的,再使用变量i去循环g,i的值就产生混乱了,第一个循环时i还是10,所以第一个值是20,此时,i值已经被赋成了20,所以第二次循环再执行i+(i+j)时,就得到41,同理第三次循环执行i+(i+j)时,i已经是41了,第四次.......所以最终输出20,41,84,171
将循环的变量i换为k后,变量名不再重复,赋值也就不再混乱了,从而和list(g)的结果一致了
4 回答4.5k 阅读✓ 已解决
1 回答3.4k 阅读✓ 已解决
4 回答3.9k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
1 回答4.5k 阅读✓ 已解决
2 回答501 阅读✓ 已解决
1 回答4k 阅读✓ 已解决
这个要解释起来可能会比较绕,生成器只会在被需要的时候才会执行代码,但这里还需要另一个知识前提,那就是推导式中的变量是临时变量,不会影响到其他变量的,简单来看个例子:
不记得是那个python版本处理了这个问题了,在一些比较旧的版本里是没有变量保护机制的,至少我用的是 3.6 版本有。同理,来看下这个和题目中比较接近的:
你猜,这里会打印什么,是
[0, 1, 2, 3]
。生成器中的 i 是受保护的,因此与外部变量 i 无关,它的取值就一定是 0123。再看一个:
这里 i 是受保护的,而
a
并没有,由于后续 a 的值是 5,所以打印语句中生成器应该是<gen 5 + 0, 5 + 1, ...>
的存在。好,终于能谈谈题目中的代码了。
第一行的
g=(i for i in range(4))
中,i 是受保护的,所以它的迭代永远都是0~3
这里的 j 也属于受保护的,在第一次循环中,它的值就是 g 初始时的产出 0~3。而这里的 i 不受保护,只是进行变量绑定,在生成器生成数据时才获取其值。
第一次循环后 g 的值:
第二次循环, 推导式中j就是生产的值,虽然此时
i=10
,但i是后续绑定的,所以出生产为 i+0, i+1, i+2,i+3 第二次循环后 g 的值:最后打印语句时,i的值是循环体最后一次的值(10),所以打印输出
20, 21, 22, 23
顺便对楼上的:
做个解释。
在第二个循环体开始前,g 生成器是
<gen i+i+0, i+i+1, ..., i+i+3>
。for i in g
表明,从 g 生成的数据赋值给 i 。从生成器获得i+i+0
,要生成数据了,i得代入此时的值了,此时是什么值呢?没错, i 是上一次循环体最后一个值(10)所以生成 20,将 20 赋值给 i;第二次循环在从生成器中获取了
i+i+1
,此时 i 是 20(上一次循环给赋值的,难点在这),所以生成是 41,再次赋值给 i;第三次循环,取得
i+i+2
此时 i 的值是 41, 所以得到的生成值是 84, 再次赋值给 i;...等