Python 字节码中的列表构造

问题描述 投票:0回答:1

这个Python代码:

import dis
def f():
    a=[1,2,3]

dis.dis(f)

生成此输出:

  2           0 RESUME                   0

  3           2 BUILD_LIST               0
              4 LOAD_CONST               1 ((1, 2, 3))
              6 LIST_EXTEND              1
              8 STORE_FAST               0 (a)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE

我对数组构建过程感到困惑。

我的猜测是:

  • BUILD_LIST 0
    设置一个标记,或者列表指针的占位符?.
  • LOAD_CONST 1
    将 #1 常量的所有元素(恰好是该元组)放入机器堆栈中,从最后一个到第一个。
  • LIST_EXTEND 1
    弹出并将当时机器堆栈中的一个元素添加到列表中,直到到达标记(我不知道
    1
    的用途是什么)。
  • STORE_FAST
    现在我们的指针位于顶部,所以这条指令最终将指针绑定到恰好是
    a
    的 #0 标识符。

这是正确的吗? (编辑:不,猜测不正确)

python bytecode cpython
1个回答
0
投票

Cpython 在基于堆栈的虚拟机中执行其字节码。 现在让我们开始逐行解释

dis
输出。

  • BUILD_LIST  0

这里

BUILD_LIST
opcode
0
oparg
。这将创建一个空列表并将其推入堆栈顶部。

case TARGET(BUILD_LIST): {
    PyObject *list =  PyList_New(oparg); // create empty list
    if (list == NULL)
        goto error;
    // Skipped other parts of the code for brevity.
    PUSH(list); // push it onto the top of the stack
    DISPATCH();
}

此操作后堆栈状态将是

堆栈
列表(指向 PyObject 的指针)
  • LOAD_CONST  1

这会将 (1, 2, 3)

(即 
co_consts[1]
)推到堆栈顶部

case TARGET(LOAD_CONST): { PREDICTED(LOAD_CONST); PyObject *value = GETITEM(consts, oparg); Py_INCREF(value); PUSH(value); DISPATCH(); }
堆栈状态现已更改为

堆栈(1,2,3)列表(指向 PyObject 的指针)
  • LIST_EXTEND 1
    
    
这将首先

pop

 的可迭代对象
堆栈的顶部(即 
(1, 2, 3)
)。
然后 
PEEK(oparg)
 将获取堆栈的第 
oparg
(即 1)个元素,而不删除它(即 
list
 对象)。

PEEK(n)

 扩展为 
#define PEEK(n) (stack_pointer[-(n)])

case TARGET(LIST_EXTEND): { PyObject *iterable = POP(); PyObject *list = PEEK(oparg); PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); // Skipped other parts of the code for brevity. Py_DECREF(none_val); Py_DECREF(iterable); DISPATCH(); }

_PyList_Extend

 API 使用可迭代就地扩展了列表

现在堆栈状态将是:

堆栈列表(现在填充有 1、2、3)
  • STORE_FAST
    
    

STACK.pop()

 存储到局部变量 
a
(
co_varnames\[var_num\]
)

© www.soinside.com 2019 - 2024. All rights reserved.