首先写一个demo.py,里面只有一句:
JasonLee 2011.08.21 15:08
i = 1
接着写一个test.py,内容如下:
import dis
source = open('./demo.py').read()
co = compile(source, './demo.py', 'exec')
dis.dis(co)
source = open('./demo.py').read()
co = compile(source, './demo.py', 'exec')
dis.dis(co)
输出:
1 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (i)
6 LOAD_CONST 1 (None)
9 RETURN_VALUE
3 STORE_NAME 0 (i)
6 LOAD_CONST 1 (None)
9 RETURN_VALUE
利用Python库提供的dis工具,可以对其反汇编,得到如上结果(开头的1表示对应的源码行号)。
所以,对于i = 1这样的语句,Python的虚拟机是一步一步执行上述指令的。
PyEval_EvalFrameEx是通过switch/case语句来执行指令的,对应的LOAD_CONST代码如下:
caseLOAD_CONST:
x=GETITEM(consts,oparg);
Py_INCREF(x);
PUSH(x);
gotofast_next_opcode;
consts是指PyCodeObject中的常量:consts=co->co_consts;
首先是从consts常量元组中获取元素,oparg为0,即获取((PyTupleObject*)op)
->ob_item[i];。
接着增加引用计数。
然后将其压栈:
#defineBASIC_PUSH(v)
(*stack_pointer++ = (v))
#definePUSH(v)
{ (void)(BASIC_PUSH(v),
\
……
这里的stack_pointer是帧(活动记录)对应的栈指针:stack_pointer=f->f_stacktop;
所以执行到这里,就是从consts变量元组中取出第0个元素(值为1),将其push到当前活动记录对应的栈中。
接下来是LOAD_VALUE:
caseSTORE_NAME:
w=GETITEM(names,oparg);
v=POP();
if((x=f->f_locals)
!=NULL) {
if(PyDict_CheckExact(x))
err=PyDict_SetItem(x,w,v);
else
err=PyObject_SetItem(x,w,v);
Py_DECREF(v);
if(err==
0)continue;
break;
}
PyErr_Format(PyExc_SystemError,
"no locals found when storing %s",
PyObject_REPR(w));
break;
首先从names中取出第0个元素,即i;
接着进行出栈操作,把刚才进展的1给POP出来;
最后把键值对(key - value)保存到局部符号表中:f->f_locals。
最后两句是返回语句。
JasonLee 2011.08.21 15:08
本文详细解析了Python代码执行流程,利用dis工具反汇编代码,揭示了虚拟机如何逐步执行指令,包括LOAD_CONST、STORE_NAME等关键操作,深入理解Python解释器内部工作原理。
51万+

被折叠的 条评论
为什么被折叠?



