Python列表初始化与值 - 实现过程?

时间:2017-07-18 20:00:39

标签: python list constructor python-internals

如何使用方括号实现Python列表初始化?它是否会在创建列表之前逐个调用一些预先存在的函数,例如__setitem__,或者是否有一个单独的函数,它接受可变数量的参数并创建一个列表?

l = [1, 2, 3, 4, 5]

例如,上面的列表是如何创建的?我感兴趣的是在源代码中构建列表的过程。实际代码本身,或执行将列表存储到内存中的步骤。

2 个答案:

答案 0 :(得分:3)

您可以编译该特定代码段并使用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类'构造函数。

语言的语法解析源代码以构建解析树,以便创建列表并准备在运行时使用。

有关列表对象实现的详细信息,请查看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分配对象。

答案 1 :(得分:3)

就语言规范而言,它构建了一个列表,并且没有关于它如何做到的承诺。如果您希望使用公共挂钩来自定义流程或其他内容,请不要。你不能这样做。

如果你想看看实现如何适用于你所使用的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

您可以看到带有参数BUILD_LIST的{​​{1}}操作码。这会从Python字节码参数堆栈中弹出5个值,并从中构建一个列表。

查看5的{​​{3}}:

BUILD_LIST

我们可以看到它使用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设置项目,这些例程是列表source的一部分。不涉及Python端API - 不查找PyList_SET_ITEM名称,不list__setitem__