Python 闭包
·
一、什么是闭包?
通俗定义
闭包 = 嵌套函数 + 引用外部函数变量 + 外部函数返回嵌套函数
- 在一个外部函数里定义一个内部函数
- 内部函数使用了外部函数的变量 / 参数
- 外部函数把内部函数作为返回值返回
- 这个被返回的内部函数 + 它引用的外部变量,就叫闭包
官方理解
闭包让内部函数可以访问并保留外部函数作用域的变量,即使外部函数已经执行结束、退出作用域,变量依然存活。
二、闭包的必备条件(4 条缺一不可)
- 必须是函数嵌套(函数里定义函数)
- 内部函数必须引用外部函数的变量
- 外部函数必须返回内部函数对象(不能加括号)
- 外部函数的变量不会随函数结束销毁(被闭包保留)
三、最简单的闭包示例
# 外部函数
def outer(msg):
# 外部函数变量
text = msg
# 内部函数(嵌套函数)
def inner():
# 内部函数引用外部变量 → 核心!
print(f"闭包访问的变量:{text}")
# 外部函数返回内部函数(不加括号!)
return inner
# 调用外部函数,得到内部函数对象
func = outer("Hello Closure!")
# 调用内部函数
func() # 输出:闭包访问的变量:Hello Closure!
关键说明
outer()执行完后,按理说text应该被销毁- 但因为闭包,
inner保留了对text的引用 - 后续调用
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
六、闭包的核心用途
- 保存函数状态(计数器、缓存、记录历史)
- 装饰器底层实现(Python 装饰器本质就是闭包)
- 工厂函数(批量生成功能相似的函数)
- 数据封装(替代简单类,比类更轻量)
七、闭包常见坑与解决方法
坑 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 类(简单对比)
| 场景 | 闭包 | 类 |
|---|---|---|
| 保存少量状态 | 推荐,轻量、代码少 | 重量级 |
| 复杂功能 | 不适合 | 适合 |
| 装饰器 | 必须用闭包 | 无法替代 |
简单状态保存用闭包,复杂逻辑用类
总结
- 闭包三要素:嵌套函数、引用外部变量、返回内部函数
- 核心能力:保留外部函数变量状态,延长变量生命周期
- 关键字:修改外部变量用
nonlocal - 主要用途:计数器、装饰器、工厂函数、状态保存
- 避坑:循环闭包用默认参数立即绑定变量
更多推荐
所有评论(0)