闭包的关键在于定义时的作用域嵌套结构而非调用位置;需满足三条件:嵌套定义、引用外层局部变量、外层函数返回内层函数对象。

闭包的形成,关键不在函数在哪被调用,而在于它在哪被定义——确切地说,是定义时所处的作用域嵌套结构决定了它能否成为闭包。
闭包的本质是“定义时锁定的作用域链”
Python 在函数定义阶段就静态确定了其能访问的变量范围。只要一个函数在另一个函数内部定义,并且引用了外层函数的局部变量,这个内层函数就是闭包函数。这种绑定与后续在哪里调用完全无关。
- 外层函数返回内层函数对象(不加括号),而不是调用结果
- 内层函数体内必须直接使用外层函数的局部变量(不能只是传参进去)
- 外层函数执行完毕后,其局部变量本该销毁,但因被内层函数引用而被“延长寿命”
为什么调用位置不影响闭包行为
比如 outter() 返回 inner,之后在模块顶层或另一个函数里调用 f(),它依然能打印出 name='egon'。这是因为 inner 对象自带一份对外层作用域的引用,就像打包了一小块“环境快照”。
- 作用域查找顺序固定:局部 → 外层嵌套 → 全局 → 内置
- 闭包让“外层嵌套”这一层始终可触达,哪怕外层函数早已退出
- 可以用 f.__closure__ 查看闭包引用的单元格,f.__code__.co_freevars 查看引用的变量名
常见误区:嵌套定义 ≠ 自动闭包
仅仅把函数写在另一个函数里面,还不足以构成闭包。必须同时满足“引用外部局部变量”这个条件。
- 如果内层函数只用全局变量或参数,没有捕获外层局部变量,就不是闭包
- 如果外层函数返回的是 inner()(带括号),那返回的是调用结果,不是函数对象,更谈不上闭包
- 用 nonlocal 修改外层变量,不影响闭包判定,只影响变量是否可变
实用判断方式
三步快速验证:
- 查定义:函数是否定义在另一个函数内部?
- 查引用:它是否直接读取了外层函数的局部变量(非参数、非全局)?
- 查返回:外层函数是否返回了该函数对象本身?
三个条件都满足,就是一个标准闭包。它的行为由定义那一刻的作用域嵌套关系决定,稳定且可预测。











