Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Closure (闭包)

✅ 一、什么是闭包?(一句话概念)

闭包 = 内层函数 + 捕获的外层变量(环境)

即:函数记住了定义时的作用域,而不是执行时的作用域。

✅ 二、最经典示例

def make_adder(x):
    def adder(y):
        return x + y   # 使用外部函数的变量 x
    return adder

add10 = make_adder(10)
print(add10(5))   # 15

✅ adder() 内部用到了外部函数 make_adder() 的变量 x

✅ 即使 make_adder() 已经执行完,adder() 仍然保留 x=10

这就是闭包。

✅ 三、闭包的三个特征

要成为闭包,必须满足:

  1. 外层函数有局部变量
  2. 内层函数使用了这个局部变量
  3. 外层函数返回内层函数

例如:

def outer():
    x = 100
    def inner():
        print(x)
    return inner

✅ 四、为什么需要闭包?(用途)

4.1 记住状态(不用类也能实现“带状态的函数”)

def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c = counter()
print(c())  # 1
print(c())  # 2

4.2 替代类的简易数据存储

def make_db_conn(url):
    def query(sql):
        print("connect:", url)
        return f"run SQL: {sql}"
    return query

db = make_db_conn("postgres://root")
db("SELECT 1")

4.3 装饰器底层依赖闭包

def logger(fn):
    def wrapper(*args, **kwargs):
        print("calling:", fn.__name__)
        return fn(*args, **kwargs)
    return wrapper

4.4 工厂函数(返回带配置的函数)

def multiply(n):
    return lambda x: x * n

double = multiply(2)
print(double(10))  # 20

✅ 五、闭包变量为什么会“记住值”?

Python 的函数对象有一个属性:__closure__

add10 = make_adder(10)
print(add10.__closure__)

输出类似:

(<cell at 0x...: int object at 0x...>,)

闭包中的变量储存在 cell 中,不会因为外层函数结束而销毁。

✅ 六、nonlocal 的用途

闭包中如果要修改外部变量,必须加 nonlocal:

def counter():
    n = 0
    def inc():
        nonlocal n
        n += 1
        return n
    return inc

否则 Python 会认为你在定义新的局部变量。

✅ 七、闭包的高级问题:循环中变量捕获(坑点)

常见坑:

funcs = []
for i in range(5):
    funcs.append(lambda: i)

print([f() for f in funcs])  

输出:

[4, 4, 4, 4, 4]

因为 i 最终变成了 4。

正确方式:

7.1 默认参数绑定

funcs = []
for i in range(5):
    funcs.append(lambda i=i: i)

7.2 用 partial

from functools import partial
funcs = [partial(lambda x: x, i) for i in range(5)]

✅ 八、闭包 vs lambda 的关系

lambda 也是函数,所以也能产生闭包:

def make():
    x = 3
    return lambda y: x + y

闭包不是 lambda 的专属,也不是函数式编程特性,但在 Python 里非常常用。

✅ 九、实战:构造带缓存 cache 的函数

比如你的爬虫里可以这样用:

def with_cache(fn):
    cache = {}
    def wrapper(x):
        if x in cache:
            return cache[x]
        cache[x] = fn(x)
        return cache[x]
    return wrapper

@with_cache
def slow_fn(x):
    time.sleep(1)
    return x * 2

闭包让 cache 永远保留。