torlee 发表于 2017-5-6 07:04:51

[笔记]Python虚拟机如何执行“i = 1”

首先写一个demo.py,里面只有一句:
i = 1

接着写一个test.py,内容如下:

import dis
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




利用Python库提供的dis工具,可以对其反汇编,得到如上结果(开头的1表示对应的源码行号)。

所以,对于i = 1这样的语句,Python的虚拟机是一步一步执行上述指令的。




PyEval_EvalFrameEx是通过switch/case语句来执行指令的,对应的LOAD_CONST代码如下:

       case LOAD_CONST:
x = GETITEM(consts, oparg);
Py_INCREF(x);
PUSH(x);
goto fast_next_opcode;




consts是指PyCodeObject中的常量:consts=co->co_consts;

首先是从consts常量元组中获取元素,oparg为0,即获取((PyTupleObject*)op)
->ob_item;。

接着增加引用计数。

然后将其压栈:

#define BASIC_PUSH(v)   (*stack_pointer++ = (v))
#define PUSH(v)         { (void)(BASIC_PUSH(v), \
……




这里的stack_pointer是帧(活动记录)对应的栈指针:stack_pointer=f->f_stacktop;

所以执行到这里,就是从consts变量元组中取出第0个元素(值为1),将其push到当前活动记录对应的栈中。




接下来是LOAD_VALUE:

      case STORE_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
页: [1]
查看完整版本: [笔记]Python虚拟机如何执行“i = 1”