python 使用PyDict_SetItemString进行引用计数

omqzjyyz  于 2023-05-27  发布在  Python
关注(0)|答案(3)|浏览(207)

我想知道当一个新的值被设置到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_SetItemPyDict_SetItemString都没有说明如何处理字典的替换。

cnjp1d6j

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()的一个薄薄的 Package

2)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
就是给出答案的函数。在这个函数中,你可以找到关键的代码,特别是调用:

Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */

其递减旧值的REF计数。

qyyhg6bp

qyyhg6bp2#

被接受的答案似乎会导致人们得出错误的结论,就像在评论中看到的那样(实际上没有明确说明引用是否被盗)。这让我很困惑,因为我看到其他帖子说它没有,正如所提到的,文档也没有说它会窃取引用。事实上,在代码库和文档中工作的人也明确指出它不会窃取引用:https://bugs.python.org/issue39153
作为回应,我决定查看insertdict()的接受答案中链接的代码,虽然它实际上减少了对旧值的引用,正如接受答案中所述,但它也增加了对新值的引用。由于旧值可能也是在某个点插入的,因此我们可以假设它的引用在被递减之前也被递增。
这意味着引用 * 没有 * 被盗,并且您应该像往常一样将引用计数减少到传递给PyDict_Set函数的任何值(除非文档中另有说明)。
再次为回答一个老问题道歉,但是当搜索旧版本Python的引用和PyDict_Set函数的信息时,这个问题仍然出现在顶部附近,我想为其他人省去我所经历的麻烦。

ego6inou

ego6inou3#

PyDict_SetItem将指向传递给它的(pyobject)值的指针按字面意思放入字典中?所以我不能将引用减少到第一个或后续PyDict_SetItem之后传递的值,对吗?(请原谅我的愚蠢问题,这可能是显而易见的)

相关问题