Python如何存储闭包中的变量
我们知道,在Python中方法内部的局部变量都保存在栈帧中,一旦方法结束栈帧被销毁,则局部变量也一并被销毁。有如下Python程序
1 | def outer(): |
在outer方法被调用时,outer所对应的栈帧在栈上被创建,局部变量x和y的值被保存在栈帧中。当outer方法执行完毕之后,outer的栈帧被销毁,outer栈帧中的局部变量的值也会被销毁。此时局部变量被保存在哪里才能使得接下来函数func被调用时能得到正确的x和y的值呢?
使用如下代码可以打印outer函数和func函数的字节码
1 | import dis |
在CPython2.7中运行以上程序,得到结果如下
>>>>>>>>>>>>>> outer <<<<<<<<<<<<<<<<
2 0 LOAD_CONST 1 (2333)
3 STORE_DEREF 0 (x)
3 6 LOAD_CONST 2 (666)
9 STORE_DEREF 1 (y)
5 12 LOAD_CLOSURE 0 (x)
15 LOAD_CLOSURE 1 (y)
18 BUILD_TUPLE 2
21 LOAD_CONST 3 (<code object inner at 0x105100e30, file "", line 5>)
24 MAKE_CLOSURE 0
27 STORE_FAST 0 (inner)
8 30 LOAD_FAST 0 (inner)
33 RETURN_VALUE
>>>>>>>>>>>>>> func <<<<<<<<<<<<<<<<<
6 0 LOAD_DEREF 0 (x)
3 LOAD_DEREF 1 (y)
6 BINARY_ADD
7 RETURN_VALUE
上面我们需要重点观察的就是 STORE_DEREF
和 LOAD_DEREF
指令
指令 | 功能 |
---|---|
STORE_DEREF | 把栈顶元素保存到函数对象的 __closure__ 属性的指定下标中 |
LOAD_DEREF | 根据 index 从函数的 __closure__ 属性中取得变量 |
由字节码我们知道Python中闭包的变量是被保存在函数对象中的,我们也可以利用如下的代码获取一个函数对象中的所有的闭包变量:
1 | for param in func.__closure__: |
打印结果为
2333
666
参考:
Python闭包研究
Where does Python store the name binding of function closure?
Disassembler for Python bytecode
本文链接:
https://www.nosuchfield.com/2018/11/12/How-Python-stores-variables-in-closures/
版权声明:
本博客所有文章均采用
CC BY-NC-SA 4.0 许可协议,转载请注明出处!