python 闭包获取循环数据经典 bug

问题代码

python 复制代码
def create_functions():
    functions = []
    for i in range(3):
        # 创建一个函数,期望捕获当前循环的i值
        functions.append(lambda: print(f"My value is: {i}"))
    return functions

# 创建三个函数
f0, f1, f2 = create_functions()

# 调用这些函数
f0()  # 期望输出 "My value is: 0"
f1()  # 期望输出 "My value is: 1"
f2()  # 期望输出 "My value is: 2"

但是实际输出为

text 复制代码
My value is: 2
My value is: 2
My value is: 2

类似的,也可以不是用 lambda 表达式,而是使用函数实现闭包

python 复制代码
# 依旧有问题
def create_functions():
    functions = []
    for i in range(3):
        def func():
            print(f"My value is: {i}")
        functions.append(func)
    return functions

问题原因解释

产生这样问题的原因是:python 闭包捕获了同一个外部变量 i,并且是通过变量名 i 而非 i 的地址作为索引(这一点很关键,虽然实际要比这个复杂,但是可以理解为就是通过名称确定某个变量的!

  • 如果不是通过变量 i 的字符串名字进行索引,也不会出现这个问题,实际上在 for i in range(3) 过程中给你,i 的地址是一直变的
  • 所以在最后 f0f1f2 都用过名字 i 来找内存,找到了最后的那个 2 对应的内存地址!

两种解决方案

方案 1:把值通过变量传进去,此时闭包引用的是 func 的局部变量 x,而每一个函数实际都是不同的

python 复制代码
def create_functions():
    functions = []
    for i in range(3):
        def func(x):
            return lambda: print(f"My value is: {x}")
        functions.append(func(i))
    return functions

# 创建三个函数
f0, f1, f2 = create_functions()

# 调用这些函数
f0()  # 期望输出 "My value is: 0"
f1()  # 期望输出 "My value is: 1"
f2()  # 期望输出 "My value is: 2"

方案 2:使用函数入参默认值,因为 python 在定义函数默认值时,需要计算出来(这也是另外一个经常出 bug 的问题)

python 复制代码
def create_functions():
    functions = []
    for i in range(3):
        def func(x=i):
            print(f"My value is: {x}")
        functions.append(func)
    return functions

# 创建三个函数
f0, f1, f2 = create_functions()

# 调用这些函数
f0()  # 输出 "My value is: 0"
f1()  # 输出 "My value is: 1"
f2()  # 输出 "My value is: 2"

总结

在产生闭包(尤其是 lambda 表达式这种比较隐蔽时)时,一定要注意闭包中对外部变量的引用是否在发生改变,要仔细思考这些改变是否符合预期

不过,只要知道原理,相信可以很好的处理这些情况

相关推荐
菜到离谱但坚持18 分钟前
【小白零基础】RAG+LangChain 搭建私有知识库问答系统(完整可运行代码+超详细教程+避坑指南)
python·langchain·rag
知识的宝藏23 分钟前
Xpaht self::div 轴语法
开发语言
keykey6.24 分钟前
卷积神经网络(CNN):让AI学会“看“
开发语言·人工智能·深度学习·机器学习
ss27324 分钟前
【入门OJ题解】分苹果问题(Python/Java/C 实现)
java·c语言·python
IsJunJianXin27 分钟前
谷歌搜索cookie NID逆向生成
开发语言·python·google搜索·sgss·nid-cookie·算法生成nid·google-cookie
暗夜猎手-大魔王30 分钟前
转载--Hermes Agent 11 | 智能审批与平台化安全:当 AI 来守护 AI
人工智能·python·安全
AIFQuant30 分钟前
量化私募回测系统:高质量股票/外汇历史数据 API 选型与接入
python·websocket·金融·ai量化
Mr.Daozhi33 分钟前
Playwright实战:抓取Meta Ad Library动态页面的三级降级策略
爬虫·python·自动化·playwright·meta广告
weikecms36 分钟前
美团霸王餐报名API接口
java·开发语言
财经资讯数据_灵砚智能1 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年6月5日
大数据·人工智能·python·ai·信息可视化·自然语言处理·灵砚智能