闭包是嵌套函数捕获并携带外部局部变量形成的有记忆函数。它依赖legb作用域规则,通过__closure__等属性验证,适用于状态封装、装饰器等场景,但需警惕循环引用陷阱。

闭包和嵌套函数是Python中理解函数式编程和作用域机制的关键。它们不是语法糖,而是支撑装饰器、回调、状态封装等实用功能的底层能力。掌握它们,关键不在记住定义,而在看清变量生命周期和引用关系。
嵌套函数:函数内部定义函数,作用域天然受限
嵌套函数可以访问外部函数的局部变量(非赋值时),但不能直接修改——这是LEGB规则的体现(Local → Enclosing → Global → Built-in)。例如:
def outer(x):
def inner():
print(x) # ✅ 可读取x
# x = 10 # ❌ 报UnboundLocalError,除非声明nonlocal
return inner
注意:嵌套函数只有在被返回或传出去后,才可能“脱离”外层函数执行环境;否则它只是outer执行时的一个临时对象。
立即学习“Python免费学习笔记(深入)”;
闭包:嵌套函数 + 捕获的自由变量 = 有记忆的函数
当嵌套函数引用了外部函数的局部变量,并且该嵌套函数被返回(或以其他方式传出)时,就形成了闭包。此时,即使outer已执行完毕,inner仍能访问并携带x的值。
f = outer("hello")
f() # 输出 "hello"
验证是否为闭包:
– 查看 f.__closure__:不为None,且含cell对象
– 查看 f.__code__.co_freevars:显示被捕获的变量名(如 ('x',))
– 访问 f.__closure__[0].cell_contents:拿到实际值
闭包的典型用途:延迟绑定与状态保持
闭包让函数自带轻量级状态,无需类即可实现数据封装:
- 生成带预设参数的函数:比如创建多个不同倍率的乘法器
- 避免全局变量:计数器、配置缓存等场景下,用闭包比用global更安全清晰
- 实现简单装饰器骨架:装饰器本质就是接收函数、返回新函数的闭包
常见陷阱:循环中创建闭包时,所有函数共享同一个变量引用(如for循环中的i)。解决方法是用默认参数捕获当前值:lambda i=i: print(i) 或在闭包内立即绑定。
何时用闭包?何时用类?
闭包适合单一行为+少量状态;类更适合多方法、复杂状态管理或需要继承/实例化时。一个闭包等价于一个只含一个方法的类,但更轻量、更函数式。如果后续要加方法或属性,及时重构为类更可持续。










