关于一段Python生成器代码的运行逻辑疑问
关于一段Python生成器代码的运行逻辑疑问
嘿,我来帮你拆解这段代码的运行逻辑,搞懂为什么输出是[20, 21, 22, 23]~
首先得抓住两个核心点:
- 生成器表达式是懒加载的:它不会在定义时立刻计算结果,只有当你真正去遍历它(比如用
list()转成列表)的时候才会执行内部逻辑。 - 生成器里的外部变量是后期绑定的:不是定义生成器那会儿就把变量值固定下来,而是等到迭代的时候才去取变量的当前值。
现在咱们一步步梳理执行流程:
第一步:初始化生成器
先看开头的函数:
def add(n,i): return n+i def test(): for i in range(4): yield i
add()就是简单的两数求和,test()是个生成器函数,调用后会依次产出0、1、2、3这四个值。
然后执行g = test(),此时g只是一个待激活的生成器对象,还没开始产出任何值。
第二步:两次循环重赋值生成器
进入for n in [1,10]的循环:
- 第一次循环(
n=1):g被重新赋值为生成器表达式(add(n,i) for i in g)。注意!这时候这个表达式并没有执行,只是把“要做的操作”记录下来——它知道要遍历当前的g(也就是test()生成器),对每个i调用add(n,i),但这里的n只是引用外部变量,没有绑定具体值。 - 第二次循环(
n=10):g再次被赋值为新的生成器表达式(add(n,i) for i in g)。同样,这个表达式也只是“待命”状态,此时外部的n已经变成10,但生成器里的n依然是引用,没固定值。
第三步:触发生成器计算(关键!)
当执行print(list(g))时,终于要让生成器干活了!这时候会一层层触发迭代:
- 最外层是第二次循环创建的生成器,它需要遍历内部的
g(也就是第一次循环创建的生成器),对每个i执行add(n,i)——这时候它会取当前的n值,也就是最后一次循环的10。 - 遍历第一次循环创建的生成器时,它需要遍历最开始的
test()生成器,对每个i执行add(n,i)——这里的n同样取当前的10,而不是之前的1! - 具体计算过程:
test()产出0→ 第一次生成器计算add(10, 0)=10→ 第二次生成器计算add(10, 10)=20test()产出1→add(10,1)=11→add(10,11)=21test()产出2→add(10,2)=12→add(10,12)=22test()产出3→add(10,3)=13→add(10,13)=23
最后把这些结果收集成列表,就得到了[20, 21, 22, 23]。
如果想对比验证,你可以把生成器表达式改成列表推导式(比如g = [add(n,i) for i in g]),因为列表推导式是立刻计算的,输出会变成[11,12,13,14]——这就是因为每次循环时n的值被立刻绑定,不会等到最后才取。
备注:内容来源于stack exchange,提问作者user29062757
相关产品推荐
相关产品推荐

