人人都会AI编程

闭包的形成条件、变量保存机制

更新时间:2026-07-12

闭包是 Python 函数进阶中的一个重要概念,它让函数能够“记住”定义时的环境。理解闭包,对于编写装饰器、回调函数和封装状态的代码至关重要。

闭包的形成条件

一个闭包的形成,需要同时满足以下三个条件:

  1. 存在嵌套函数:在一个外部函数内部,定义了另一个内部函数。
  2. 内部函数引用了外部函数的局部变量(这些变量称为自由变量)。
  3. 外部函数将内部函数作为返回值返回

只有内部函数被返回到外部作用域时,它才可能被其他地方调用,从而让闭包真正“闭合”外部变量。如果内部函数仅在外部函数内部调用,那它只是一个普通的嵌套函数,算不上闭包。

简单示例

def outer(message):
    def inner():
        print(f"记住的信息: {message}")
    return inner

closure_func = outer("你好")
closure_func()  # 输出:记住的信息: 你好

这里 inner 引用了 outer 的局部变量 message,并且 outer 返回了 inner,所以 inner 就是一个闭包。

变量保存机制

闭包之所以能“记住”外部变量,是因为 Python 在创建内部函数时,会在函数对象的 closure 属性中保存对外部变量引用的单元格对象(cell object)

具体过程:

  • 当 Python 编译遇到嵌套函数,且内部函数引用了外部函数的变量时,会为这些变量创建一个 cell 对象。
  • 外部函数执行时,这些变量不再存储为普通的局部变量,而是被放入 cell 对象中,从而实现值的“共享”和“持久化”。
  • 内部函数的 closure 属性会记录这些 cell 对象,即使外部函数执行完毕、其局部命名空间已经销毁,通过 closure 仍然可以访问到当时的变量值。

验证代码

def outer(x):
    y = 10
    def inner():
        return x + y
    return inner

f = outer(5)
print(f.__closure__)              # (<cell at 0x...: int object at ...>, <cell at 0x...: int object at ...>)
print(f.__closure__[0].cell_contents)  # 5
print(f.__closure__[1].cell_contents)  # 10
print(f())                         # 15

即便 outer 函数已经返回,我们仍能通过闭包访问到 xy 的值。

常见陷阱:循环中的闭包

闭包保存的是变量本身的引用,而不是值的副本。如果在循环中创建多个闭包,它们都引用同一个循环变量,最终所有闭包看到的都是循环结束后的值。

funcs = []
for i in range(3):
    def inner():
        return i
    funcs.append(inner)

print([f() for f in funcs])   # 输出: [2, 2, 2],而不是 [0, 1, 2]

解决方法:在每次迭代时用一个默认参数来“快照”当前值:

funcs = []
for i in range(3):
    def inner(i=i):
        return i
    funcs.append(inner)
print([f() for f in funcs])   # 输出: [0, 1, 2]

或者再包一层函数来创建独立的变量作用域。

闭包的实际用途

  • 实现装饰器(带参数的装饰器核心就是闭包)。
  • 创建带有状态的简单函数对象,替代只有一两个方法的类。
  • 回调函数或事件处理中保存上下文数据。
  • 在函数式编程中实现柯里化、偏函数等模式。

闭包是 Python 函数式编程的基石,掌握它的形成条件和变量保存机制,写装饰器和理解高阶函数会变得非常自然。