← 返回首页

Python 闭包是什么?

在 Python 中,闭包(Closure) 是一种特殊的函数机制。简单来说,闭包就是一个**“自带背包”的函数**。它不仅包含了函数本身的代码,还“打包”携带了它在定义时所处的外部环境(变量)。

要构成一个标准的闭包,必须同时满足以下三个条件:

  1. 必须有一个嵌套函数(函数内部定义函数)。
  2. 嵌套函数必须引用外层函数的变量。
  3. 外层函数必须返回这个嵌套函数。

1. 闭包的直观示例

def outer_func(msg):
    # 外层函数的局部变量
    message = msg  

    # 嵌套函数
    def inner_func():
        # 引用了外层函数的变量 message
        print(f"Message: {message}")  

    # 返回嵌套函数(注意:这里没有加括号,返回的是函数对象本身)
    return inner_func  

# 调用 outer_func,传入参数
hello_func = outer_func("Hello")
world_func = outer_func("World")

# 执行返回的函数
hello_func()  # 输出: Message: Hello
world_func()  # 输出: Message: World

在这个例子中,当 outer_func 执行完毕后,按理说它的局部变量 message 应该被销毁。但由于 inner_func 引用了它,并且被返回到了外部,Python 会将 message 变量与 inner_func 绑定在一起,形成一个闭包。无论 hello_func 被传递到哪里,它都能记住自己诞生时的 message 值。

2. 闭包的核心价值:数据隐藏与状态保持

闭包最大的好处是可以避免使用全局变量,同时让函数拥有自己的“私有状态”。它提供了一种将数据(变量)与操作数据的函数绑定在一起的方式,非常接近面向对象编程中“类”的概念。

3. 查看闭包变量:__closure__ 属性

你可以通过函数的 __closure__ 属性来验证闭包的存在。它会返回一个包含 cell 对象的元组,里面保存了被引用的外部变量:

print(hello_func.__closure__)       # (<cell at 0x...: str object at 0x...>,)
print(hello_func.__closure__[0].cell_contents)  # Hello

4. 闭包中的经典陷阱:循环变量绑定

在使用闭包时,最容易踩坑的是在循环中创建闭包:

def create_funcs():
    funcs = []
    for i in range(3):
        # 注意:这里的 i 是延迟绑定的
        funcs.append(lambda: i)  
    return funcs

my_funcs = create_funcs()
for f in my_funcs:
    print(f())  # 输出全是 2,而不是 0, 1, 2

为什么会这样? 因为闭包捕获的是变量 i 的引用,而不是它在循环时的值。当循环结束时,i 变成了 2,所以所有闭包在执行时读取到的都是 2。

解决办法:利用默认参数在定义时立即绑定当前值:

funcs.append(lambda x=i: x)  # 将当前的 i 作为默认值传给 x

总结:闭包是 Python 实现高阶函数、装饰器(Decorator)以及函数式编程的基础。理解闭包,本质上就是理解 Python 中**“函数是一等公民”以及“变量是引用”**这两个核心概念。