一、什么是闭包?

通俗定义

闭包 = 嵌套函数 + 引用外部函数变量 + 外部函数返回嵌套函数

  • 在一个外部函数里定义一个内部函数
  • 内部函数使用了外部函数的变量 / 参数
  • 外部函数把内部函数作为返回值返回
  • 这个被返回的内部函数 + 它引用的外部变量,就叫闭包

官方理解

        闭包让内部函数可以访问并保留外部函数作用域的变量,即使外部函数已经执行结束、退出作用域,变量依然存活。


二、闭包的必备条件(4 条缺一不可)

  1. 必须是函数嵌套(函数里定义函数)
  2. 内部函数必须引用外部函数的变量
  3. 外部函数必须返回内部函数对象(不能加括号)
  4. 外部函数的变量不会随函数结束销毁(被闭包保留)

三、最简单的闭包示例

# 外部函数
def outer(msg):
    # 外部函数变量
    text = msg

    # 内部函数(嵌套函数)
    def inner():
        # 内部函数引用外部变量 → 核心!
        print(f"闭包访问的变量:{text}")

    # 外部函数返回内部函数(不加括号!)
    return inner

# 调用外部函数,得到内部函数对象
func = outer("Hello Closure!")
# 调用内部函数
func()  # 输出:闭包访问的变量:Hello Closure!

关键说明

  1. outer() 执行完后,按理说 text 应该被销毁
  2. 但因为闭包,inner 保留了对 text 的引用
  3. 后续调用 func() 依然能访问到这个变量

四、闭包保存「状态」(最常用功能)

        闭包最大的作用:记住历史数据,保存函数状态比如:实现一个计数器,每次调用都在上次结果上 + 1

def counter():
    # 闭包要保存的状态:计数初始值
    count = 0

    def add():
        # 声明使用外部函数的变量(必须加 nonlocal)
        nonlocal count
        count += 1
        return count

    return add

# 创建计数器实例
c1 = counter()

# 多次调用,状态会保留
print(c1())  # 1
print(c1())  # 2
print(c1())  # 3

# 新的实例,独立状态
c2 = counter()
print(c2())  # 1

关键字:nonlocal

  • 在内部函数修改外部函数变量时,必须加 nonlocal
  • 只读取不修改,不需要加

五、闭包的高级用法:带参数的闭包

def power(exponent):
    # 内部函数接收参数
    def base(num):
        return num ** exponent
    return base

# 生成平方函数、立方函数
square = power(2)
cube = power(3)

print(square(5))  # 25
print(cube(5))    # 125

六、闭包的核心用途

  1. 保存函数状态(计数器、缓存、记录历史)
  2. 装饰器底层实现(Python 装饰器本质就是闭包)
  3. 工厂函数(批量生成功能相似的函数)
  4. 数据封装(替代简单类,比类更轻量)

七、闭包常见坑与解决方法

        坑 1:循环中创建闭包,变量延迟绑定

错误代码:

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

f1, f2, f3 = create_functions()
print(f1(), f2(), f3())  # 全部输出 2(不是预期 0,1,2)

        原因:闭包延迟绑定,循环结束后 i=2,所有函数共用同一个 i

        ✅ 解决方法:给内部函数加默认参数(立即绑定)

def create_functions():
    funcs = []
    for i in range(3):
        def func(n=i):  # 立即绑定当前 i
            return n
        funcs.append(func)
    return funcs

f1, f2, f3 = create_functions()
print(f1(), f2(), f3())  # 0 1 2 ✔

        坑 2:修改外部变量忘记加 nonlocal

        修改必须声明 nonlocal,否则会报错 / 创建局部变量


八、闭包判断:closure 属性

        Python 提供内置属性判断是否是闭包:

func = outer("test")
# 打印闭包保存的变量
print(func.__closure__)
# 查看闭包变量的值
print(func.__closure__[0].cell_contents)  # test
  • 不是闭包:__closure__ = None
  • 是闭包:__closure__ 包含引用的外部变量

九、闭包 VS 类(简单对比)

场景 闭包
保存少量状态 推荐,轻量、代码少 重量级
复杂功能 不适合 适合
装饰器 必须用闭包 无法替代

简单状态保存用闭包,复杂逻辑用类


总结

  1. 闭包三要素:嵌套函数、引用外部变量、返回内部函数
  2. 核心能力:保留外部函数变量状态,延长变量生命周期
  3. 关键字:修改外部变量用 nonlocal
  4. 主要用途:计数器、装饰器、工厂函数、状态保存
  5. 避坑:循环闭包用默认参数立即绑定变量
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐