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

Python递归作用域间变量如何传递?以斐波那契字典缓存为例

问题场景

我编写了一个带缓存的递归函数计算斐波那契数列,用字典缓存已计算的结果:

def fib_dict2(n,d):
    if n in d.keys():
        return d[n]
    else:
        var = fib_dict2(n-1,d) + fib_dict2(n-2,d)
        d[n]=var
        return var
d = {0:1,1:1}
print(fib_dict2(5,d))
print(d)

运行结果:

8
{0: 1, 1: 1, 2: 2, 3: 3, 4: 5, 5: 8}

我发现函数内部修改字典d后,全局作用域的d也跟着改变了。之前以为变量是所在作用域独有的,事实并非如此吗?Python中作用域间的变量共享机制是怎样的?


核心原因:可变对象的引用传递

Python里的变量传递逻辑,核心区分可变对象和不可变对象:

  • 不可变对象(如int、str、tuple):传递的是值的副本,修改时会创建新对象,不同作用域的变量互不影响。
  • 可变对象(如dict、list、set):传递的是对象的内存引用,所有指向这个引用的变量,操作的都是同一个底层对象。

你的代码里,字典d属于可变对象。当你把它作为参数传给fib_dict2函数时,函数参数d和全局的d指向的是同一个字典对象。所以在函数里执行d[n]=var这类修改对象内部状态的操作时,全局的字典自然会同步变化——因为它们本质上是同一个对象。


关于作用域的澄清

你之前的误解是混淆了「变量名的作用域」和「变量指向的对象」:

  • 变量名确实是作用域独有的:函数内的d和全局的d是两个独立的变量名,但它们指向了同一个对象。
  • 如果在函数里给d重新赋值(比如d = {2:2}),此时函数内的d会指向新的对象,和全局的d彻底无关——因为你修改的是变量名的指向,而非对象本身。

举个简单例子验证这个逻辑:

def test(d):
    d[3] = 3  # 修改对象内部,全局d会同步变化
    d = {4:4}  # 重新赋值变量名,与全局d不再关联
d = {1:1}
test(d)
print(d)  # 输出:{1: 1, 3: 3}

总结

  • 可变对象的引用传递特性,让不同作用域的变量名可以共享同一个对象,修改对象内部状态会同步反映到所有指向它的变量。
  • 变量名的作用域是隔离的,但对象本身可以跨作用域共享,关键在于你是修改对象内部,还是重新赋值变量名。

内容的提问来源于stack exchange,提问作者Steven Doria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:12:17