Python简单内建表达式创建


python简单内建表达式创建

a = 1
b = []
c = {}
d = 'string'

python实际执行的指令码如下:

  1           0 LOAD_CONST               0 (1)
              2 STORE_NAME               0 (a)

  2           4 BUILD_LIST               0
              6 STORE_NAME               1 (b)

  3           8 BUILD_MAP                0
             10 STORE_NAME               2 (c)

  4          12 LOAD_CONST               1 ('string')
             14 STORE_NAME               3 (d)
             16 LOAD_CONST               2 (None)
             18 RETURN_VALUE
None
  • 每行的具体信息代表如下:源码行号,指令偏移量,指令符号,指令参数,实际参数值。
  • 在python的ceval.c中,python使用_PyEval_EvalFrameDefault函数执行栈帧。
  • 又由frameobject可知,python使用for(;;)循环,判断指令码,执行指令码。
  • 由于是简单内建表达式创建,影响的作用域在f_locals中,现使用表格,代表f_locals的mapping对象。

    keyvalue
  • 由于栈在运行过程中一直使用,故同样使用表格表示栈。

    栈底

a = 1

a = 1python执行的字节码为:

    1           0 LOAD_CONST               0 (1)
                2 STORE_NAME               0 (a)
  • LOAD_CONST

    case TARGET(LOAD_CONST): {
        PREDICTED(LOAD_CONST);
        PyObject *value = GETITEM(consts, oparg);
        Py_INCREF(value);
        PUSH(value);
        DISPATCH();
    }
    • PyObject *value = GETITEM(consts, oparg):宏定义函数,#define GETITEM(v, i) PyTuple_GetItem((v), (i)),该代码的功能是从consts中取出一个数,压入虚拟机的运行时栈中,其中consts是f->f_code->co_consts,f是当前活跃的栈帧对象。oparg是传入的指令码参数。
    • PUSH(value):将consts中的值取出推入运行时栈中。
    • 目前运行时栈为:
    栈底
    1
    • f_locals为:
    keyvalue
  • STORE_NAME

    case TARGET(STORE_NAME): {
        PyObject *name = GETITEM(names, oparg);
        PyObject *v = POP();
        PyObject *ns = f->f_locals;
        int err;
        if (ns == NULL) {
            _PyErr_Format(tstate, PyExc_SystemError,
                          "no locals found when storing %R", name);
            Py_DECREF(v);
            goto error;
        }
        if (PyDict_CheckExact(ns))
            err = PyDict_SetItem(ns, name, v);
        else
            err = PyObject_SetItem(ns, name, v);
        Py_DECREF(v);
        if (err != 0)
            goto error;
        DISPATCH();
    }
    
    • PyObject *name = GETITEM(names, oparg);:从符号表中获得符号,oparg为指令码参数,此时为0.
    • PyObject *v = POP();:栈顶元素弹出。
    • 检查f->f_locals
    • PyDict_SetItem(ns, name, v):向PyDict即f_locals中设置键和值。
    • 目前运行时栈为:
    栈底
    • f_locals为:
    keyvalue
    a1

b = []

b = []执行的字节码如下:

  2           4 BUILD_LIST               0
              6 STORE_NAME               1 (b)
  • BUILD_LIST:

    case TARGET(BUILD_LIST): {
        PyObject *list =  PyList_New(oparg);
            if (list == NULL)
                goto error;
            while (--oparg >= 0) {
                PyObject *item = POP();
                PyList_SET_ITEM(list, oparg, item);
            }
            PUSH(list);
            DISPATCH();
    }
    • PyObject *list = PyList_New(oparg);:创建一个新的list列表。
    • 如果指令码参数>=0,则弹出运行时栈中oparg个元素,填入list中。
    • 将list推入运行时栈。
    • 目前运行时栈为:
    栈底
    list
    • f_locals为:
    keyvalue
    a1
  • STORE_NAME:功能已在a=1时分析,即弹出运行时栈,在names元组中取值,然后存入f_locals中。

    • 目前运行时栈为:
    栈底
    • f_locals为:
    keyvalue
    a1
    blist

c = {}

c = {}执行的字节码如下:

  3           8 BUILD_MAP                0
             10 STORE_NAME               2 (c)
  • BUILD_MAP

    case TARGET(BUILD_MAP): {
        Py_ssize_t i;
        PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
        if (map == NULL)
            goto error;
        for (i = oparg; i > 0; i--) {
            int err;
            PyObject *key = PEEK(2*i);
            PyObject *value = PEEK(2*i - 1);
            err = PyDict_SetItem(map, key, value);
            if (err != 0) {
                Py_DECREF(map);
                goto error;
            }
        }
    
        while (oparg--) {
            Py_DECREF(POP());
            Py_DECREF(POP());
        }
        PUSH(map);
        DISPATCH();
    }
    • _PyDict_NewPresized((Py_ssize_t)oparg);:创建一个新字典。
    • 根据oparg判断是否应当初始化字典。PEEK即选取栈中的第几个元素。栈中的元素在while循环中出栈。
    • 将map推到栈中
    • 目前运行时栈为:
    栈底
    map
    • f_locals mapping为:
    keyvalue
    a1
  • STORE_NAME

    • 执行STORE_NAME后,运行时栈为:
    栈底
    • f_locals为:
    keyvalue
    a1
    blist
    cmap

d = 'string'

d = 'string',执行的字节码如下:

4          12 LOAD_CONST               1 ('string')
           14 STORE_NAME               3 (d)

执行过程同a=1,不再赘述,执行后

  • 运行时栈为:

    栈底
  • f_locals为:

    keyvalue
    a1
    blist
    cmap
    d'string'

e = set()

  5          16 LOAD_NAME                4 (set)
             18 CALL_FUNCTION            0
             20 STORE_NAME               5 (e)
  • LOAD_NAME

    case TARGET(LOAD_NAME): {
        PyObject *name = GETITEM(names, oparg);
        PyObject *locals = f->f_locals;
        PyObject *v;
        if (locals == NULL) {
            _PyErr_Format(tstate, PyExc_SystemError,
                        "no locals when loading %R", name);
            goto error;
        }
        if (PyDict_CheckExact(locals)) {
            v = PyDict_GetItemWithError(locals, name);
            if (v != NULL) {
                Py_INCREF(v);
            }
            else if (_PyErr_Occurred(tstate)) {
                goto error;
            }
        }
        else {
            v = PyObject_GetItem(locals, name);
            if (v == NULL) {
                if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError))
                    goto error;
                _PyErr_Clear(tstate);
            }
        }
        if (v == NULL) {
            v = PyDict_GetItemWithError(f->f_globals, name);
            if (v != NULL) {
                Py_INCREF(v);
            }
            else if (_PyErr_Occurred(tstate)) {
                goto error;
            }
            else {
                if (PyDict_CheckExact(f->f_builtins)) {
                    v = PyDict_GetItemWithError(f->f_builtins, name);
                    if (v == NULL) {
                        if (!_PyErr_Occurred(tstate)) {
                            format_exc_check_arg(
                                    tstate, PyExc_NameError,
                                    NAME_ERROR_MSG, name);
                        }
                        goto error;
                    }
                    Py_INCREF(v);
                }
                else {
                    v = PyObject_GetItem(f->f_builtins, name);
                    if (v == NULL) {
                        if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
                            format_exc_check_arg(
                                        tstate, PyExc_NameError,
                                        NAME_ERROR_MSG, name);
                        }
                        goto error;
                    }
                }
            }
        }
        PUSH(v);
        DISPATCH();
    }
    • 代码先从局部作用域查找变量,如果未找到,就从全局作用域查找代码,如果仍然没有找到,就去内建作用域中查找。
    • 将找到的值,推入运行时栈中。

return

栈帧的返回值

16 LOAD_CONST               2 (None)
18 RETURN_VALUE
  • LOAD_CONST:加载常量None
  • RETURN_VALUE:

    case TARGET(RETURN_VALUE): {
      retval = POP();
      assert(f->f_iblock == 0);
      assert(EMPTY());
      f->f_state = FRAME_RETURNED;
      f->f_stackdepth = 0;
      goto exiting;
    }

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Python简单内建表达式创建


我的朋友,理论是灰色的,而生活之树是常青的!