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
相关产品推荐
相关产品推荐

