Python list initialization with values--实现过程?
Python list initialization with values--implementation process?
Python列表用方括号初始化是怎么实现的?它是一个一个地调用一些预先存在的函数,例如 __setitem__
,直到创建列表,还是有一个单独的函数接受可变数量的参数并创建一个列表?
l = [1, 2, 3, 4, 5]
例如,上面的列表是如何创建的?我对在源代码中构建列表的过程很感兴趣。实际代码本身,或将列表存储到内存中所执行的步骤。
您可以编译该特定代码片段并使用 dis
:
检查字节码
In [1]: import dis
In [2]: code = compile('l = [1, 2, 3, 4, 5]', '', 'exec')
In [3]: dis.dis(code)
1 0 LOAD_CONST 0 (1)
3 LOAD_CONST 1 (2)
6 LOAD_CONST 2 (3)
9 LOAD_CONST 3 (4)
12 LOAD_CONST 4 (5)
15 BUILD_LIST 5
18 STORE_NAME 0 (l)
21 LOAD_CONST 5 (None)
24 RETURN_VALUE
特别是第 15 行,BUILD_LIST
,实际构建列表的地方。实际上没有调用构造函数或函数,如本例所示:
In [1108]: dis.dis(compile('l = list()', '', 'exec'))
1 0 LOAD_NAME 0 (list)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 STORE_NAME 1 (l)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
在第 3 行 CALL_FUNCTION
中,调用了 list
class' 构造函数。
该语言的语法会解析源代码以构建解析树,以便在运行时创建并准备好使用列表。
关于列表对象的详细实现,请看here。
编辑:找到字节码的实现细节。 Here 是的。 BUILD_LIST
:
TARGET(BUILD_LIST)
x = PyList_New(oparg);
if (x != NULL) {
for (; --oparg >= 0;) {
w = POP();
PyList_SET_ITEM(x, oparg, w);
}
PUSH(x);
DISPATCH();
}
break;
对比CALL_FUNCTION
:
TARGET(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)
DISPATCH();
break;
}
后者进行实际的函数调用,而前者使用 PyList_New
分配对象。
就语言规范而言,它构建了一个列表,但没有关于它如何做到这一点的承诺。如果您希望使用 public 挂钩来自定义流程或其他内容,那不行。你不能那样做。
如果您想了解该实现如何适用于您所使用的 Python 版本,您可以向下挖掘。例如,在 CPython 3.6 上,使用 dis
,Python 反汇编程序:
>>> import dis
>>> dis.dis(lambda: [1,2,3,4,5])
1 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_CONST 4 (4)
8 LOAD_CONST 5 (5)
10 BUILD_LIST 5
12 RETURN_VALUE
您可以看到带有参数 5
的 BUILD_LIST
操作码。这会从 Python 字节码参数堆栈中弹出 5 个值,并从中构建一个列表。
查看 BUILD_LIST
的 3.6 source:
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();
}
我们可以看到它使用 PyList_New
分配列表对象并使用 PyList_SET_ITEM
设置项目,这些例程是列表 C API 的一部分。不涉及 Python 端 API - 没有查找 list
名称,没有 __setitem__
或 append
.
Python列表用方括号初始化是怎么实现的?它是一个一个地调用一些预先存在的函数,例如 __setitem__
,直到创建列表,还是有一个单独的函数接受可变数量的参数并创建一个列表?
l = [1, 2, 3, 4, 5]
例如,上面的列表是如何创建的?我对在源代码中构建列表的过程很感兴趣。实际代码本身,或将列表存储到内存中所执行的步骤。
您可以编译该特定代码片段并使用 dis
:
In [1]: import dis
In [2]: code = compile('l = [1, 2, 3, 4, 5]', '', 'exec')
In [3]: dis.dis(code)
1 0 LOAD_CONST 0 (1)
3 LOAD_CONST 1 (2)
6 LOAD_CONST 2 (3)
9 LOAD_CONST 3 (4)
12 LOAD_CONST 4 (5)
15 BUILD_LIST 5
18 STORE_NAME 0 (l)
21 LOAD_CONST 5 (None)
24 RETURN_VALUE
特别是第 15 行,BUILD_LIST
,实际构建列表的地方。实际上没有调用构造函数或函数,如本例所示:
In [1108]: dis.dis(compile('l = list()', '', 'exec'))
1 0 LOAD_NAME 0 (list)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 STORE_NAME 1 (l)
9 LOAD_CONST 0 (None)
12 RETURN_VALUE
在第 3 行 CALL_FUNCTION
中,调用了 list
class' 构造函数。
该语言的语法会解析源代码以构建解析树,以便在运行时创建并准备好使用列表。
关于列表对象的详细实现,请看here。
编辑:找到字节码的实现细节。 Here 是的。 BUILD_LIST
:
TARGET(BUILD_LIST)
x = PyList_New(oparg);
if (x != NULL) {
for (; --oparg >= 0;) {
w = POP();
PyList_SET_ITEM(x, oparg, w);
}
PUSH(x);
DISPATCH();
}
break;
对比CALL_FUNCTION
:
TARGET(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)
DISPATCH();
break;
}
后者进行实际的函数调用,而前者使用 PyList_New
分配对象。
就语言规范而言,它构建了一个列表,但没有关于它如何做到这一点的承诺。如果您希望使用 public 挂钩来自定义流程或其他内容,那不行。你不能那样做。
如果您想了解该实现如何适用于您所使用的 Python 版本,您可以向下挖掘。例如,在 CPython 3.6 上,使用 dis
,Python 反汇编程序:
>>> import dis
>>> dis.dis(lambda: [1,2,3,4,5])
1 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (3)
6 LOAD_CONST 4 (4)
8 LOAD_CONST 5 (5)
10 BUILD_LIST 5
12 RETURN_VALUE
您可以看到带有参数 5
的 BUILD_LIST
操作码。这会从 Python 字节码参数堆栈中弹出 5 个值,并从中构建一个列表。
查看 BUILD_LIST
的 3.6 source:
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();
}
我们可以看到它使用 PyList_New
分配列表对象并使用 PyList_SET_ITEM
设置项目,这些例程是列表 C API 的一部分。不涉及 Python 端 API - 没有查找 list
名称,没有 __setitem__
或 append
.