我们知道,在Python中方法内部的局部变量都保存在栈帧中,一旦方法结束栈帧被销毁,则局部变量也一并被销毁。有如下Python程序1
2
3
4
5
6
7
8
9
10def ():
x = 2333
y = 666
def inner():
return x + y
return inner
func = outer()
在outer方法被调用时,outer所对应的栈帧在栈上被创建,局部变量x和y的值被保存在栈帧中。当outer方法执行完毕之后,outer的栈帧被销毁,outer栈帧中的局部变量的值也会被销毁。此时局部变量被保存在哪里才能使得接下来函数func被调用时能得到正确的x和y的值呢?
使用如下代码可以打印outer函数和func函数的字节码1
2
3
4
5
6import dis
print '>>>>>>>>>>>>>> outer <<<<<<<<<<<<<<<
dis.dis(outer)
print '>>>>>>>>>>>>>> func <<<<<<<<<<<<<<<<
dis.dis(func)
在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 ()
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 指令指令功能把栈顶元素保存到函数对象的 __closure__ 属性的指定下标中
根据 index 从函数的 __closure__ 属性中取得变量
由字节码我们知道Python中闭包的变量是被保存在函数对象中的,我们也可以利用如下的代码获取一个函数对象中的所有的闭包变量:1
2for param in func.__closure__:
print param.cell_contents
打印结果为2333
666