python闭包是嵌套函数,它记住定义时外部作用域的非全局变量(自由变量),且外部函数返回该内部函数;变量绑定发生在定义时,但实际引用外部变量而非复制值。

Python闭包是指一个函数对象,它不仅包含函数本身,还“记住”了其定义时所在作用域中的变量(即自由变量),即使外部函数已经返回,这些变量仍能被内部函数访问。
闭包的三个必要条件
要构成闭包,必须同时满足:
- 存在一个嵌套函数(内部函数定义在另一个函数内部)
- 内部函数引用了外部函数的**非全局**变量(即自由变量)
- 外部函数返回了内部函数(注意:是函数对象本身,不是调用结果,即不带括号)
变量绑定发生在定义时,而非调用时
这是理解闭包行为的关键。Python 中的自由变量在**内部函数被定义时**就与外部作用域中的变量名绑定,但实际值的“快照”并非立即捕获——而是形成一条指向外部变量的引用链。这意味着如果外部变量后续被修改,闭包中看到的值也会变(除非变量不可变且被重新赋值)。
常见误区是认为闭包会“复制”变量值。实际上它保存的是对变量的引用。例如:
立即学习“Python免费学习笔记(深入)”;
def make_multiplier(n):
return lambda x: x * n
<p>funcs = []
for i in range(3):
funcs.append(make_multiplier(i))</p><h1>此时每个闭包都绑定了各自的 i(0、1、2),输出 0, 2, 4</h1><p>for f in funcs:
print(f(2))</p>经典陷阱:循环中创建闭包时的 late binding
当在循环中直接创建闭包并引用循环变量时,由于变量绑定延迟到闭包被调用时才求值,而那时循环变量已固定为最终值,会导致所有闭包表现一致:
# ❌ 错误写法:全部输出 9
funcs = []
for i in range(3):
funcs.append(lambda x: x * i)
<p>print([f(2) for f in funcs]) # [4, 4, 4] —— 因为 i 最终是 2</p><h1>✅ 正确写法:用默认参数强制绑定当前值</h1><p>funcs = []
for i in range(3):
funcs.append(lambda x, i=i: x * i)</p><p>print([f(2) for f in funcs]) # [0, 2, 4]</p>这里 i=i 利用了默认参数在函数定义时求值的特性,把当前循环轮次的 i 值“快照”下来。
如何验证一个函数是不是闭包
检查函数对象的 __closure__ 属性:
- 若为 None,说明不是闭包
- 若为元组(如 (
| ,) | ),则它是闭包,每个 cell 对应一个被捕获的自由变量 - 可通过 func.__closure__[0].cell_contents 查看具体值










