
本文详解 python 装饰器中 `inner` 函数为何能直接访问调用时传入的参数(如 `num`),揭示闭包机制与函数调用链的本质关系,并通过代码还原和执行流程分析消除常见误解。
在你提供的代码中,inner(num) 看似“凭空”获得了 num 的值,其实这并非魔法,而是 Python 函数调用机制与闭包(closure)特性的自然结果。关键在于:inner 并非在定义时就绑定 num,而是在被调用时才接收该参数——它本质上是一个标准的、带参数的嵌套函数,其参数 num 来自外部对装饰后函数的显式调用。
让我们还原 @facto_decorator 的等价写法:
def facto(num):
if num == 1:
return 1
else:
return num * facto(num-1)
# @facto_decorator 等价于:
facto = facto_decorator(facto)此时,facto 已不再是原始函数,而是 facto_decorator(facto) 的返回值——即 inner 函数对象。因此,当你执行:
facto(5) # 实际上等价于 inner(5)
Python 解释器会将 5 作为实参传递给 inner,num 就是这个传入的参数。inner 的签名 def inner(num): 明确声明了它接受一个名为 num 的位置参数,这与普通函数完全一致。
立即学习“Python免费学习笔记(深入)”;
⚠️ 需要澄清一个常见误区:
outer 函数(即 facto_decorator)本身确实不接收 num —— 它只接收被装饰的函数 func 作为参数;而 inner 是在 facto_decorator 返回后、被单独调用时才接收 num。二者处于不同调用层级:
- facto_decorator(func) → 接收函数,返回 inner
- inner(num) → 接收数值,执行逻辑并缓存
这种设计正是装饰器模式的核心:outer 负责“包装准备”,inner 负责“运行时拦截与增强”。inner 对 num 的访问,不依赖于 outer 的局部变量(outer 甚至没有 num 这个变量),而纯粹来自函数调用时的参数传递。
✅ 补充验证:你可以打印 inner.__code__.co_varnames 查看其参数名,或用 import inspect; print(inspect.signature(inner)) 确认它明确期望一个 num 参数。
总结来说:inner 访问 num 不是因为它“继承”了外部作用域中的 num,而是因为它本身就是被设计为接收 num 的函数。装饰器的语法糖 @ 只是让这种包装更简洁,但底层仍是清晰的函数调用链:facto(a) → inner(a) → func(a)。理解这一点,就抓住了 Python 装饰器与闭包协同工作的本质。










