6月2日 01:31

Python 闭包是什么?变量怎么被记住的?

闭包是一个函数记住了自己被创建时的作用域里的变量,即使那个作用域已经执行完毕。Python 里闭包最常见的用途:工厂函数、延迟计算、替代简单类。

闭包怎么产生的

python
def make_counter(start=0): count = start def counter(): nonlocal count count += 1 return count return counter c = make_counter(10) print(c()) # 11 print(c()) # 12

make_counter 执行完了,count 变量按理应该被销毁。但 counter 函数内部引用了 count,Python 会把 countcounter 绑在一起——这就是闭包。counter 闭包了 count 变量。

nonlocal 声明告诉 Python count 不是局部变量,而是外层作用域的变量。不加 nonlocalcount += 1 会在 counter 内部创建一个新的局部变量 count,而不是修改外层的。

闭包存储在哪里

闭包变量存在函数的 __closure__ 属性里:

python
print(c.__closure__) # (<cell at 0x...: int object at ...>,) print(c.__closure__[0].cell_contents) # 12

每个被闭包的变量是一个 cell 对象。这就是 Python 实现闭包的底层机制。

常见用途

1. 工厂函数

根据参数生成不同的函数:

python
def power(exp): def f(base): return base ** exp return f square = power(2) cube = power(3) print(square(5)) # 25 print(cube(5)) # 125

2. 缓存/记忆化

python
def memoize(fn): cache = {} def wrapper(*args): if args not in cache: cache[args] = fn(*args) return cache[args] return wrapper @memoize def fib(n): if n < 2: return n return fib(n-1) + fib(n-2) print(fib(100)) # 瞬间出结果

cachewrapper 闭包,不需要全局变量。这就是装饰器能工作的基础——装饰器本质上就是闭包。

3. 替代简单类

只有状态 + 一个方法的场景,闭包比类轻量:

python
# 闭包方式 def make_accumulator(initial=0): total = initial def add(value): nonlocal total total += value return total return add acc = make_accumulator() print(acc(10)) # 10 print(acc(20)) # 30

追问

闭包和类怎么选?

有多个方法或复杂状态管理用类。只有一个操作 + 简单状态用闭包。闭包更函数式,类更面向对象。

闭包会导致内存泄漏吗?

会。被闭包的变量不会在函数返回后释放,只要闭包函数还活着,变量就一直在。长期存活的闭包(如事件监听器、回调)要注意。

lambda 能形成闭包吗?

能。lambda x: x + offset 里的 offset 就是被闭包的变量。但 lambda 不能用 nonlocal,所以无法修改外层变量,只能读取。

标签:Python