print(id([]) == id([]))
# prints 'True'
print(id(list()) == id(list()))
# prints 'False'
x = []
y = []
print(id(x) == id(y))
# prints 'False'
为什么list()
与[]
的行为有不同,就上述代码而言?
在第三次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);
当列表被释放时,保存元素指针的缓冲区被释放,但(最大空闲列表大小最大)标题包含有关对象类型,引用计数,容量等内容的信息.goes on the free list:
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)
}
第一个[]
创建的列表在第二个[]
表达式之前消失,因此它的标题位于空闲列表中,然后它被第二个[]
重用。 id
值基于此标头的地址,因此两个列表具有相同的ID值。
相比之下,list()
通过tp_new
和tp_init
,而list
的tp_new
是PyType_GenericNew
,它没有通过相同的自由名单。 PyType_GenericNew
碰巧在不同的内存中分配两个列表,产生不同的ID值。
id(object)
返回对象的id。
如果变量引用的对象相等(具有相同的内容),则==
表达式的计算结果为True。
所以当你每次创建一个新对象时使用list()
构造函数,并且它的id是不同的,因此它的计算结果为false,即使新对象被立即丢弃,它首先被创建,因此它是不同的id。
相反,[]
是文字(创建对象的更快方式)并且始终具有相同的ID,但是当它创建新对象时,新对象也获得它的新ID。
TLDR; []
是一个文字,因此有一个固定的ID,list()
创建一个新的对象,x=[]
y=[]
创建一个新的对象x和y,因此x
和y
的id不一样,list()
每次创建一个新的对象,因此不同的id每次通话。
此外x = []
将比x = list()
更快,但这只是一个脚注,我不知道如何使它变小,并把它像脚注:)