You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python列表推导式、全局for、函数内for生成lambda列表的行为差异

问题背后的核心机制:Python闭包的迟绑定特性

所有lambda函数都是引用了外部变量i的闭包,Python闭包的变量取值遵循迟绑定规则:变量的值只会在闭包被调用时才查找,不会在闭包定义时就固定下来,这是你看到不同写法结果不同的根本原因。

另外首先需要纠正一个误解:你观察到plus_n_符合预期只是测试代码的巧合,和它定义在顶层作用域没有任何关系。你只要把测试代码的循环变量名改成j,就会发现plus_n_的所有输出也全部是7,和另外两种写法结果完全一致:

# 修改测试循环的变量名
for j in range(len(plus_n)):
    print('plus_n[{}]({})={}'.format(j,3,plus_n[j](3)))
    print('plus_n_[{}]({})={}'.format(j,3,plus_n_[j](3)))
    print('plus_n__[{}]({})={}'.format(j,3,plus_n__[j](3)))
    print()

三种写法的差异详解

1. 列表推导式生成的plus_n

Python 3中列表推导式拥有独立的作用域,循环结束后该作用域内的i最终值为range(MAX)的最后一个元素4。所有lambda被调用时,查找的都是这个已经固定为4的i,因此所有计算结果都是3+4=7。

2. 顶层循环生成的plus_n_

你原测试代码的循环变量正好也叫i,和lambda引用的全局i是同一个变量。每次调用lambda时,全局i正好是当前测试循环的取值,所以刚好匹配你的预期。如果修改测试循环变量名,所有lambda调用时取到的都是全局i最后一次赋值的4,结果全部为7。

3. 函数内生成返回的plus_n__

all_plus_n函数执行时,内部循环的i最终值为4。函数执行结束后,闭包会保留对函数作用域内这个i的引用,因此所有lambda调用时取到的都是4,结果全部为7。

正确实现方法

不需要将lambda列表定义为全局变量,只需要在定义lambda时用参数默认值提前绑定当前的i即可。参数默认值会在函数定义阶段就求值固定,不会等到调用时再查找:

MAX=5
# 列表推导式写法
plus_n=[lambda x, i=i: x+i for i in range(MAX)]
# 顶层循环写法
plus_n_=[]
for i in range(MAX):
    plus_n_.append(lambda x, i=i: x+i)
# 函数返回写法
def all_plus_n():
    plus_ns=[]
    for i in range(MAX):
        plus_ns.append(lambda x, i=i: x+i)
    return plus_ns
plus_n__=all_plus_n()

修改后三种写法的运行结果完全一致,全部符合预期。

内容的提问来源于stack exchange,提问作者Jonathan alis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 07:18:03