You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

执行流程:

  1. 调用my_func() → 执行inner,打印[Inner] 开始执行
  2. 调用fn() → 执行原my_func,打印[原函数] 执行中
  3. 原my_func里调用my_func() → 此时全局my_func已经绑定到inner,所以又进入inner
  4. 循环往复,看起来像是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 08:47:22