閱讀822 返回首頁    go 京東網上商城


[筆記]Python虛擬機對函數的解釋

demo.py:

i = 1

def f():
    j = 2

f()

test.py:
import dis

source = open('./demo.py').read()
co = compile(source, './demo.py', 'exec')
print(co.co_name)
dis.dis(co)

print("\n")
fCode = co.co_consts[1]
print(fCode.co_name)
dis.dis(fCode)

輸出:
<module>
  1           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (i)

  3           6 LOAD_CONST               1 (<code object f at 0x022F5430, file "./demo.py", line 3>)
              9 MAKE_FUNCTION            0
             12 STORE_NAME               1 (f)

  6          15 LOAD_NAME                1 (f)
             18 CALL_FUNCTION            0
             21 POP_TOP             
             22 LOAD_CONST               2 (None)
             25 RETURN_VALUE        


f
  4           0 LOAD_CONST               1 (2)
              3 STORE_FAST               0 (j)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE  

對於def f():這一語句,Python虛擬機先將函數f對應的PyCodeObject入棧,然後再MAKE_FUNCTION。
        case MAKE_FUNCTION:
            v = POP(); /* code object */
            x = PyFunction_New(v, f->f_globals);
            Py_DECREF(v);
            /* XXX Maybe this should be a separate opcode? */
            if (x != NULL && oparg > 0) {
                v = PyTuple_New(oparg);
                if (v == NULL) {
                    Py_DECREF(x);
                    x = NULL;
                    break;
                }
                while (--oparg >= 0) {
                    w = POP();
                    PyTuple_SET_ITEM(v, oparg, w);
                }
                err = PyFunction_SetDefaults(x, v);
                Py_DECREF(v);
            }
            PUSH(x);
            break;

在相應代碼中,將對應的PyCodeObject和幀的全局符號表指針傳遞給PyFunction_New函數,調用之,最後將返回值入棧。
在PyFunction_New函數中,創建一個PyFunctionObject,然後初始化相應的成員信息,返回之。

而對於函數f的調用,首先將函數名入棧,再執行CALL_FUNCTION:
        case CALL_FUNCTION:
        {
            PyObject **sp;
            PCALL(PCALL_ALL);
            sp = stack_pointer;
#ifdef WITH_TSC
            x = call_function(&sp, oparg, &intr0, &intr1);
#else
            x = call_function(&sp, oparg);
#endif
            stack_pointer = sp;
            PUSH(x);
            if (x != NULL)
                continue;
            break;
        }

在這裏,將棧頂指針和參數信息傳遞給函數call_function,然後恢複棧頂指針,將返回值入棧。
最後實際上是創建了一頁幀,然後以幀作為活動環境,調用PyEval_EvalFrameEx函數。
        f = PyFrame_New(tstate, co, globals, NULL);
        if (f == NULL)
            return NULL;

        fastlocals = f->f_localsplus;
        stack = (*pp_stack) - n;

        for (i = 0; i < n; i++) {
            Py_INCREF(*stack);
            fastlocals[i] = *stack++;
        }
        retval = PyEval_EvalFrameEx(f,0);



JasonLee     2011.08.27     19:52

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

  上一篇:go Mongodb錯誤,第一次安裝沒有經驗
  下一篇:go SVN提交注意點