Python闭包捕获变量引用而非值,内部函数调用时访问外部变量当前值;循环中创建闭包易共享同一变量导致错误,可用默认参数或闭包工厂解决。

Python 闭包捕获的是变量的引用,而不是创建时的值。这意味着内部函数在调用时访问的是外部作用域中该变量的当前值,而非定义闭包时的快照。
闭包捕获的是引用,不是值
当一个嵌套函数引用了外层函数的局部变量,并且这个嵌套函数在外部函数返回后仍能访问该变量,就形成了闭包。Python 不会复制变量内容,而是将变量名绑定到外层作用域中的对象上。只要该对象还存在,闭包就能通过引用访问它。
- 如果外部变量是可变对象(如列表、字典),闭包修改它会影响所有引用该对象的地方
- 如果外部变量是不可变对象(如整数、字符串),重新赋值会改变绑定关系,但闭包仍指向原来的对象(除非变量被重新赋值)
常见陷阱:循环中创建多个闭包
在 for 循环中定义闭包时,所有闭包共享同一个变量引用,容易导致意外结果:
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs]) # 输出 [2, 2, 2],不是 [0, 1, 2]这是因为所有 lambda 都引用了同一个 i,而循环结束时 i == 2。
立即学习“Python免费学习笔记(深入)”;
-
解决方法:用默认参数捕获当前值,
lambda x=i: x - 或使用闭包工厂函数,让每次迭代生成独立的作用域
查看闭包内容的方法
可以通过函数对象的 __closure__ 属性观察闭包引用:
-
func.__closure__是一个元组,每个元素是cell对象 -
cell.cell_contents可读取当前引用的对象值 - 没有闭包时,
__closure__为None
闭包与自由变量的关系
被闭包引用但不在内部函数中定义的变量,称为“自由变量”。Python 编译器会在函数编译阶段识别自由变量,并把它们加入 __code__.co_freevars 元组。运行时,解释器通过 __closure__ 维护这些变量的实际引用。
- 自由变量必须存在于外层作用域中,否则报
UnboundLocalError - 若在内部函数中对自由变量赋值(非
nonlocal声明),Python 会将其视为局部变量,导致引用错误










