闭包

Posted on 2018-08-13 23:26  王将军之武库  阅读(154)  评论(0编辑  收藏  举报

闭包

e.g.

需要回答, 什么是闭包, CPython底层是如何实现的?

PyCodeObject

我们关注两个, co_freevarsco_cellvars

对于我们上面的那个示例, add是外层函数, do_add是嵌套函数, 我们可以通过func_code打印看看

此时图示

这时候, 只是记录了使用到的变量名, 标记下是否使用了外层的/被内层使用的变量

具体的值是在运行时确定的, 例如

此时x=5, 这个是在add的名字空间里面的, 那么, x=5是怎么传递到嵌套函数内? 嵌套函数又是如何知晓x的值?

记住这两个问题, 然后我们首先来看一个新的数据结构

PyCellObject

这是个很简单的基本对象, 有一个ob_ref指向另一个PyObject, 仅此而已

图示

作用呢?

值的确认与传递过程

调用

此时, 开始调用函数

逻辑即, 如果发现当前函数co_cellvars非空, 即表示存在被内层函数调用的变量, 那么遍历这个co_cellvars集合, 拿到集合中每个变量名在当前名字空间中的值, 然后放到当前函数的f->f_localsplus中.

这里, 我们可以知道x=5被放进去了

为什么放到f->f_localsplus中呢?

看看PyFrameObject

注意f_localsplus

创建过程

call_function的时候, new了一个PyFrameObject

原因: 因为函数中的局部变量总是固定不变的, 在编译时就能确定局部变量使用的内存空间的位置, 也能确定访问局部变量的字节码应该如何访问内存, 有了这些信息, Python就能借助静态的方法实现局部变量, 而不是动态查找PyDictObject, 提高执行效率

示例函数的f_localsplus

看一下上面赋值用的宏定义

最终得到

接下去呢? CALL_FUNCTION最后怎么处理将cell传入嵌套函数?

传递

CALL_FUNCTION 完成new一个PyFrameObject之后,

最终执行这个frame

PyEval_EvalFrameEx

查看一下dis的结果

首先LOAD_CLOSURE 0

然后, BUILD_TUPLE, 将cell对象打包成tuple, 得到('x', )

然后, 开始, 载入嵌套函数do_add, 入栈

调用MAKE_CLOSURE

来关注一下 PyFunction_SetClosure

do_addPyFunctionObjectfunc_closure指向一个tuple

注意: 这时候, 外层变量已经固定下来了!!!!!!

然后, 在嵌套函数被调用的时候

看下PyFunction_GET_CLOSURE

然后, 进入 PyEval_EvalCodeEx, 注意这里的closure参数即上一步取出来的func_closure, 即外层函数传进来的tuple

最后, 再来看一个闭包的dis

注意BUILD_TUPLE

dis结果

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
18           0 LOAD_CLOSURE             0 (x)
              3 BUILD_TUPLE              1
              6 LOAD_CONST               1 ()
              9 MAKE_CLOSURE             0
             12 STORE_FAST               2 (do_add)
 
21          15 LOAD_CLOSURE             1 (y)
             18 BUILD_TUPLE              1
             21 LOAD_CONST               2 ()
             24 MAKE_CLOSURE             0
             27 STORE_FAST               3 (do_add2)
 
24          30 LOAD_CLOSURE             0 (x)
             33 LOAD_CLOSURE             1 (y)
             36 BUILD_TUPLE              2
             39 LOAD_CONST               3 ()
             42 MAKE_CLOSURE             0
             45 STORE_FAST               4 (do_add3)
 
32          48 LOAD_FAST                2 (do_add)
             51 RETURN_VALUE

Copyright © 2024 王将军之武库
Powered by .NET 9.0 on Kubernetes