“ []”和“ list()”的行为有何不同?

Pun*_*ngh 3 python list python-3.x

print(id([]) == id([]))
# prints 'True'

print(id(list()) == id(list()))
# prints 'False'

x = []
y = []
print(id(x) == id(y))
# prints 'False'
Run Code Online (Sandbox Code Playgroud)

关于上述代码,为什么list()行为与有所不同[]

use*_*ica 5

在第三个id比较中,您将比较两个具有重叠寿命的对象的ID值。根据id函数的约定,这必须返回False 。您会看到与相同的行为list()

在前两个id比较中,所涉及的对象都具有不重叠的生存期。具有非重叠生存期的对象的ID值是否恰好相同是实现的详细信息,您不应依赖于一种或另一种方式。该行为如有更改,恕不另行通知。

在当前的CPython中,ID值恰好与之相同,[]这是因为[]使用了BUILD_LIST操作码,该操作码调用了C函数PyList_New,并PyList_New使用了释放列表头标头结构的自由列表来加速分配:

PyObject *
PyList_New(Py_ssize_t size)
{
    ...
    if (numfree) {
        numfree--;
        op = free_list[numfree];
        _Py_NewReference((PyObject *)op);
Run Code Online (Sandbox Code Playgroud)

当列表被释放时,保存元素指针的缓冲区将被释放,但是(最大空闲列表大小)包含有关对象类型,对象数量,引用计数,容量等信息的标头将进入空闲列表

static void
list_dealloc(PyListObject *op)
{
    ...
    if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op))
        free_list[numfree++] = op;
    else
        Py_TYPE(op)->tp_free((PyObject *)op);
    Py_TRASHCAN_SAFE_END(op)
}
Run Code Online (Sandbox Code Playgroud)

由第一个创建的列表在[]第二个[]表达式之前消失,因此其标题进入空闲列表,然后由第二个重新使用[]。该id值基于此标头的地址,因此两个列表具有相同的ID值。

相反,list()通过tp_newtp_init,而listtp_newPyType_GenericNew,则不在同一空闲列表中。PyType_GenericNew碰巧将两个列表分配到不同的内存中,从而产生不同的ID值。