为什么重定义生成器使用的变量会得到不符合预期的运行结果?
Python生成器惰性求值与延迟绑定问题分析
首先给出问题中的代码:
array = [1, 8, 15] gen = (x for x in array if array.count(x) > 0) array = [2, 8, 22] print(list(gen)) # 输出结果: [8]
核心原因
这个现象是Python生成器的两个特性共同导致的:
- 生成器是惰性求值的:生成器定义时不会立刻执行内部逻辑,只有当迭代生成器(本例中调用
list(gen))时,才会逐次执行过滤逻辑 - 生成器内部的自由变量是延迟绑定的:变量的值只会在实际执行逻辑时才会获取,而非生成器定义时
代码执行步骤拆解
- 执行
array = [1, 8, 15],变量array指向数组[1, 8, 15] - 执行
gen = (x for x in array if array.count(x) > 0)完成生成器定义:for x in array这部分的可迭代对象会在生成器定义时立刻求值,因此生成器后续要迭代的元素固定为[1, 8, 15]三个- 过滤条件
if array.count(x) > 0中的array属于自由变量,此时不会求值,只会在后续迭代时获取当前array的指向
- 执行
array = [2, 8, 22],变量array改为指向新数组[2, 8, 22] - 执行
list(gen)迭代生成器,开始逐元素判断:- 迭代第一个元素
x=1:查询当前array(即[2,8,22])中1的个数为0,不满足条件,被过滤 - 迭代第二个元素
x=8:查询当前array中8的个数为1,满足条件,保留 - 迭代第三个元素
x=15:查询当前array中15的个数为0,不满足条件,被过滤
最终输出结果就只有[8],原数组的1和15都被过滤掉了。
- 迭代第一个元素
拓展验证
如果把生成器改为列表推导式,会立刻执行所有逻辑,输出就会是[1, 8, 15],代码如下:
array = [1, 8, 15] res = [x for x in array if array.count(x) > 0] array = [2, 8, 22] print(res) # 输出结果: [1, 8, 15]
内容的提问来源于stack exchange,提问作者pickle rick
相关产品推荐
相关产品推荐

