閱讀425 返回首頁    go 阿裏雲 go 技術社區[雲棲]


[筆記]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[i];
接著增加引用計數。
然後將其壓棧:
#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

最後更新:2017-04-02 22:16:33

  上一篇:go 自定義menu替代TabHost中的TabWidget
  下一篇:go Android2.3 編譯出錯:No rule to make InterpAsm-x86.S