这个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 标识符。这是正确的吗? (编辑:不,猜测不正确)
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();
}
堆栈状态现已更改为
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 使用可迭代就地扩展了列表现在堆栈状态将是:
STORE_FAST
存储到局部变量
a
(
co_varnames\[var_num\]
)。