Python源码剖析[17] —— 执行引擎之框架_python struct _frame 和 typedef struct _interpreter





int main()



{



g();



}



其中图1绿色部分对应的是g的栈帧,而黄色部分对应的是f的栈帧。对于一个函数而言,其所有的局部变量和操作都在自己的栈帧中完成,而函数之间的调用则通过创建新的栈帧完成,当然,在函数调用发生时,系统会保存上一个栈帧的栈指针esp和帧指针ebp。大致上,这就是可执行文件在x86机器上的运行原理,而Python正是在执行引擎中通过不同的实现方式模拟了这一原理。 



前面我们已经知道,Python源代码经过编译之后,所有的byte code以及程序的其他信息都存放在PyCodeObject对象中,那么Python的执行引擎是否就是在这个PyCodeObject对象上进行所有的动作呢?呃,是,又不是。PyCodeObject中包含了最关键的byte code以及关于程序的所有信息。然而有一点,PyCodeObject没有包含,也不可能包含。这就是执行环境。 



什么是执行环境呢,考虑下面的一个例子: 




i = ‘Python’  




 



**def** f(): 



     i = 999 



     **print** i #1 




 



f() 



**print** i #2 





 



在1和2两个地方,都进行了同样的动作,即print i,显然,它们所对应的字节码是相同的,但是这两条语句的执行效果是不同的。这样的结果正是在执行环境的影响下产生的。在执行1处的print时,执行环境中,i的值为999;而在执行2处的print时,执行环境中i的值为“Python”。这种同样的名字对应不同的值,甚至不同的类型的情况,必须在运行时动态地被捕捉和维护。这些则不可能在PyCodeObject中被静态地存储。 



联想到x86运行程序的机理,我们可以这样来考虑。当Python调用函数f时,会在当前的运行环境之外重新创建一个新的运行环境,在这个新的运行环境中,有一个新的名字为“i”的对象,这个新的运行环境实际上可以看成是一个新的栈帧。所以在Python真正执行的时候,它的执行引擎实际上面对的并不是一个PyCodeObject对象,而是另一个家伙——PyFrameObject,这个东西就是Python对栈帧的模拟,你看,它的名字中还有个Frame呢。 



当然,对于Python而言,PyFrameObject对象不是一个我们在x86机器上看到的那个简简单单的栈帧,它实际上包含了其他更多的信息,请看: 




[frameobject.h] 



**typedef struct** \_frame **{** 



     PyObject\_VAR\_HEAD 



     **struct** \_frame  \*f\_back;  /\* previous frame, or NULL \*/ 



     PyCodeObject \*f\_code;   /\* code segment \*/ 



     PyObject \*f\_builtins;   /\* builtin symbol table (PyDictObject) \*/  



     PyObject \*f\_globals;    /\* global symbol table (PyDictObject) \*/  



     PyObject \*f\_locals;     /\* local symbol table (any mapping) \*/ 



     PyObject \*\*f\_valuestack;    /\* points after the last local \*/ 



PyObject \*\*f\_stacktop; 



…… 



     **int** f\_lasti;       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值