我不知道为什么这段代码会产生打印输出True:
rec = {"Name" : "Python", "Age":"20", "Addr" : "NJ", "Country" : "USA"}
id1 = id(rec)
del rec
rec = {"Name" : "Python", "Age":"20", "Addr" : "NJ", "Country" : "USA"}
id2 = id(rec)
print(id1 == id2)
据我所知,如果我们要更改id1中的某些内容,那么rec也将更改。那么为什么该代码不删除id1,因为rec被删除了?
如果想要特定于CPython的非常技术性的答案,请参考Python实现(我在这里假设大多数人都将其默认为当他们说“ Python”时表示):Python中许多常见的对象类型是从所谓的“自由列表”中分配的东西,它是一个数组,或者在某些情况下,我认为是一个链表,其中包含已经分配了内存的相同类型的对象。例如,这意味着,可以通过为单个字典反复重复使用相同的内存分配,而不是反复地对其进行分配/释放,来快速创建和销毁许多短期字典。
例如,对于dict
对象,可以在此处查看自由列表:https://github.com/python/cpython/blob/61289d436661025a3111065482275d49a4850b8d/Objects/dictobject.c#L252
((还有一个单独的字典键,我现在将忽略。)
[创建新的dict
时,new_dict
函数首先检查new_dict
中是否有空插槽,如果有,则重新使用它(稍作伪代码重新解释):
free_list
稍后,在PyDictObject *mp;
if (numfree) {
mp = free_list[--numfree];
_Py_NewReference((PyObject *)mp);
}
else {
// Allocate a new PyDictObject
// Note, we do NOT put this on the freelist yet since it's still in use;
// we'll do that later
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
}
中,当剩余zero个对您的对象的引用时被调用,如果dict_dealloc
上有空间,我们将对象保留在那里而不是释放其内存:
dict_dealloc
要清楚,请注意,存储在free_list
中的if (numfree < PyDict_MAXFREELIST && Py_TYPE(mp) == &PyDict_Type)
free_list[numfree++] = mp;
else
Py_TYPE(mp)->tp_free((PyObject *)mp);
确实不是意味着它们的任何键或值也都保留在内存中。这仅适用于PyDictObject
本身,其中包含指向键/值的数组的指针,以及一些其他内部簿记功能。
[如果碰巧您的初始free_list
释放了PyDictObject
中的一个插槽,那么立即创建一个新的dict(无论其内容如何)将使用相同的插槽,因此具有相同的del rec
,因为在CPython中free_list
仅返回对象的内存地址。当然,即使没有免费名单,这也很可能偶然发生。
id1是一个自变量。它已从记录分配一个值。现在,如果rec被删除,则id1中将存储一个单独的值,该值不在该字典rec中。这就是为什么不删除它的原因