我想知道当一个新的值被设置到PyDict(在C扩展中)的现有字段中时,内存管理/引用计数是如何工作的。
例如,假设字典是以以下方式创建和填充的:
myPyDict = PyDict_New();
tempPyObj = PyString_FromString("Original Value");
PyDict_SetItemString(myPyDict,"fieldname",tempPyObj);
Py_DECREF(tempPyObj);
从内存和引用计数的Angular 来看,如果有一个后续的
tempPyObj = PyString_FromString("New Value");
PyDict_SetItemString(myPyDict,"fieldname",tempPyObj);
Py_DECREF(tempPyObj);
原始值的引用计数是否自动递减(并且内存是否自动释放)?PyList_SetItem
的文档特别提到了列表的情况:This function “steals” a reference to item and discards a reference to an item already in the list at the affected position.
但是PyDic_SetItem
和PyDict_SetItemString
都没有说明如何处理字典的替换。
3条答案
按热度按时间cnjp1d6j1#
旧值的ref计数通过
PyList_SetItem
函数的逻辑自动递减。您不应该自己递减旧值。如果您想了解详细信息,请查看CPython源代码,特别是
Objects/dictobject.c
文件。1)
PyDict_SetItemString()
https://github.com/python/cpython/blob/c8e7c5a/Objects/dictobject.c#L3250-L3262
它是
PyDict_SetItem()
的一个薄薄的 Package2)
PyDict_SetItem()
https://github.com/python/cpython/blob/c8e7c5a/Objects/dictobject.c#L1537-L1565
仍然非常简单,很明显,所有与插入/替换dict中的值相关的繁重工作实际上都是由
insertdict()
完成的。3)
insertdict()
https://github.com/python/cpython/blob/c8e7c5a/Objects/dictobject.c#L1097-L1186
就是给出答案的函数。在这个函数中,你可以找到关键的代码,特别是调用:
其递减旧值的REF计数。
qyyhg6bp2#
被接受的答案似乎会导致人们得出错误的结论,就像在评论中看到的那样(实际上没有明确说明引用是否被盗)。这让我很困惑,因为我看到其他帖子说它没有,正如所提到的,文档也没有说它会窃取引用。事实上,在代码库和文档中工作的人也明确指出它不会窃取引用:https://bugs.python.org/issue39153
作为回应,我决定查看
insertdict()
的接受答案中链接的代码,虽然它实际上减少了对旧值的引用,正如接受答案中所述,但它也增加了对新值的引用。由于旧值可能也是在某个点插入的,因此我们可以假设它的引用在被递减之前也被递增。这意味着引用 * 没有 * 被盗,并且您应该像往常一样将引用计数减少到传递给
PyDict_Set
函数的任何值(除非文档中另有说明)。再次为回答一个老问题道歉,但是当搜索旧版本Python的引用和
PyDict_Set
函数的信息时,这个问题仍然出现在顶部附近,我想为其他人省去我所经历的麻烦。ego6inou3#
PyDict_SetItem将指向传递给它的(pyobject)值的指针按字面意思放入字典中?所以我不能将引用减少到第一个或后续PyDict_SetItem之后传递的值,对吗?(请原谅我的愚蠢问题,这可能是显而易见的)