Python:外部函数返回后nonlocal变量的内存存储位置问询
闭包中nonlocal变量的存储位置解析
示例代码
def g(): in_g=100 def f1(): nonlocal in_g in_g = 10 def f2(): nonlocal in_g print(in_g) return (f1,f2) (f1, f2) = g() f2() #prints 100 f1() f2() #prints 10
问题描述
内部函数f1和f2均通过闭包访问变量in_g。当外部函数g返回后,nonlocal变量in_g在内存中存储于何处?
我假设在g执行期间,in_g位于g调用对应的栈帧中,因此g、f1、f2访问in_g时指向同一栈内存地址。但如示例所示,g返回后f1和f2仍能访问同一内存地址的in_g,而此时g的栈帧已不存在。
解答
你的猜测其实只对了一半——在g执行时,in_g确实一开始在栈帧里,但当Python检测到内部函数要捕获这个变量(也就是用nonlocal声明,或者直接引用它)时,这个变量会被移到堆内存中的一个闭包对象(closure cell)里,而不是留在栈上。
具体来说:
- 当
g被调用时,Python会创建一个栈帧,但发现f1和f2都引用了in_g并且用了nonlocal,就会把in_g打包成一个cell对象,存到堆里。 - 这个cell对象会被
f1和f2的__closure__属性引用着,所以即使g的栈帧销毁了,f1和f2依然能通过这个引用找到in_g的内存位置。 - 你可以自己验证一下,执行以下代码:
print(f1.__closure__) # 会输出包含cell对象的元组 print(f1.__closure__[0].cell_contents) # 直接获取in_g的当前值
简单总结:闭包捕获的变量不会留在栈帧里,而是被放到堆上的cell对象中,由内部函数的闭包引用持有,所以外部函数返回后,这些变量依然能被访问和修改。
内容的提问来源于stack exchange,提问作者user42768
相关产品推荐
相关产品推荐

