Python闭包与装饰器赋值疑问:为何fn引用发生变化?
关于Python闭包与装饰器的两个问题解答
先明确核心逻辑:Python里的变量是指向对象的名字,而非对象本身;闭包捕获的是变量的引用,而非变量指向的对象的副本。
问题1:my_func = outer(my_func)中左侧的my_func是什么?
- 最初
def my_func(): ...执行时,是在当前作用域(比如全局)创建了一个函数对象,同时把名字my_func绑定到这个对象上。 - 执行
my_func = outer(my_func)时,先计算右侧:把当前my_func指向的原函数对象传入outer,outer执行后返回inner函数对象。 - 然后,左侧的
my_func是当前作用域里的同一个名字,它会被重新绑定到outer返回的inner对象上。
原函数对象并没有被销毁——只要还有其他名字绑定它(比如提前做orig_func = my_func),你依然能通过orig_func()调用原逻辑。只是原来的my_func名字不再指向它了,若没有其他引用,后续会被Python的垃圾回收机制清理。
问题2:为何闭包里的fn看起来引用了inner而非原函数?
这大概率是递归场景导致的误解,分两种情况拆解:
情况1:你的my_func是递归函数(内部调用了my_func名字)
闭包里的fn确实还是指向传入的原函数,但原函数内部的my_func()调用的是当前作用域中my_func名字绑定的对象——也就是已经被重新赋值的inner。
举个例子:
def outer(fn): def inner(): print("[Inner] 开始执行") fn() # fn指向原my_func print("[Inner] 执行结束") return inner def my_func(): print("[原函数] 执行中") my_func() # 这里调用的是全局作用域的my_func名字 # 重新绑定my_func到inner my_func = outer(my_func) my_func()
执行流程:
- 调用
my_func()→ 执行inner,打印[Inner] 开始执行 - 调用
fn()→ 执行原my_func,打印[原函数] 执行中 - 原
my_func里调用my_func()→ 此时全局my_func已经绑定到inner,所以又进入inner - 循环往复,看起来像是
fn()触发了inner,但本质是原函数内部的名字引用已经被修改了。
情况2:非递归场景下的误解
如果你的my_func不是递归的,那闭包里的fn一定还是指向原函数。比如普通装饰器:
def outer(fn): def inner(): print("前置逻辑") fn() print("后置逻辑") return inner def my_func(): print("原函数逻辑") my_func = outer(my_func) my_func()
输出会是:
前置逻辑 原函数逻辑 后置逻辑
这里fn()确实执行的是原函数,你看到的inner相关输出是装饰器本身的逻辑,而非fn的执行结果。
如果你的代码不是这两种情况,可以贴出具体代码,能更精准排查,但核心逻辑还是:闭包捕获的是变量的引用,而如果原函数内部依赖了被重新绑定的名字,就会出现“fn好像指向了inner”的错觉。
内容的提问来源于stack exchange,提问作者chris
相关产品推荐
相关产品推荐

