logo
33

闭包

⏱️ 25分钟

闭包(Closures):让函数“记住”它的上下文

你现在可能会困惑什么

“外层函数执行结束后,变量不应该销毁吗?”

闭包场景下,被内部函数引用的外部变量会保留。 这就是“函数带状态”。

一句话定义

闭包是“内部函数 + 被捕获的外部变量环境”。

生活类比

像专属计数器遥控器: 遥控器还在,内部计数状态也还在。

最小可运行例子

def make_counter():
    count = 0

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

    return counter

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

工厂函数示例

def make_multiplier(factor):
    def mul(x):
        return x * factor
    return mul

triple = make_multiplier(3)
print(triple(5))  # 15

课堂小测(5 分钟)

  1. 实现基础计数器闭包。
  2. 改成步长为 2 的计数器。
  3. make_discount(rate) 返回折扣函数。

课堂小测参考答案与判分点

  • 参考答案方向:能写出可运行代码,并覆盖题目中的核心条件与边界输入。
  • 判分点 1(正确性):主流程结果正确,关键分支可执行。
  • 判分点 2(可读性):变量命名清晰,结构不过度嵌套。
  • 判分点 3(健壮性):对空值、类型错误或异常输入有基础保护。

迁移任务(课后)

做一个“重试函数工厂”:make_retry(max_retry) 返回带重试的执行器。

本节验收标准

你能独立做到:

  • 解释闭包为何能保留状态
  • 正确使用 nonlocal
  • 在简单业务中使用闭包封装配置

常见报错与调试步骤(新手版)

  • 报错看不懂:先读最后一行错误类型(如 TypeErrorNameError),再回到对应代码行定位。
  • 不确定变量值:在关键位置临时 print(变量, type(变量)),先确认数据是否符合预期。
  • 改了代码却没生效:确认文件已保存、运行的是当前文件、终端环境(venv)是否正确。

常见误区

  • 误区:所有嵌套函数都是闭包。

  • 正解:必须捕获外部变量并在外部持续使用才算闭包。

  • 误区:nonlocalglobal 随意互换。

  • 正解:nonlocal 作用于外层局部作用域,global 作用于模块级变量。