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 许可协议,转载请注明出处!