python生成器的问题,大佬帮帮忙

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] 呢?

阅读 859
评论 2018-08-15 提问
    2 个回答
    • 191

    生成器的特点是并没有立即执行,而是记住'生产方式',等被调用时再执行.
    在您的这个例子中:
    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)的结果一致了