Python C扩展中的引用计数
我正在为Python写我的第一个C扩展,但对引用计数有点困惑。下面是我想做的事情。
我在一个循环中填充一个字典:
mydict = PyDict_New();
for (...)
{
pair = PyTuple_Pack(2, PyString_FromString("some string"),
PyString_FromString("some other string"));
/* at this point, the refcnt for the tuple is 1, the refcnts for the
2 string items are 2. Because according to the source, PyString_FromString
does an INCREF, and PyTuple_Pack() does an INCREF on its items
*/
PyDict_SetItem(mydict, PyString_FromString("some key"), pair);
/* At this point, the key's refcnt is 2. PyString_FromString sets it to 1 and
PyDict_SetItem INCREF's it. Ditto for pair since PyDict_SetItem also INCREF's
the value.
*/
Py_DECREF(pair);
/* pair's refcnt is 1 which makes sense to me since mydict now owns the tuple,
but the refcnt for its items are still at 2. I don't understand this part.
*/
}
return mydict;
我的引用计数正确吗?在C API的文档中,特别建议在调用PyTuple_SetItem
或PyList_SetItem
时使用PyObject_FromXXX
函数,因为它们会“窃取”引用。
但是文档没有说明PyDict_SetItem
是否也会窃取引用。我猜它不会,所以我应该这样做:
first = PyString_FromString("some string");
second = PyString_FromString("some other string");
pair = PyTuple_Pack(2, first, second);
Py_DECREF(second);
Py_DECREF(first);
我这样理解对吗?
1 个回答
7
如果你查看CPython的源代码(在Objects/tupleobject.c文件中)里关于PyTuple_Pack的部分,你会发现它确实会对每个打包的对象增加引用计数。换句话说,每当你把一个对象放进元组里,它的引用计数就会加一。
如果你使用PyTuple_New创建一个新的元组,然后再用PyTuple_SetItem来设置里面的内容,你就不需要手动减少引用计数,因为SetItem会“偷走”这些引用,自动处理好。
最后,你也可以直接使用Py_BuildValue("(ss)", "some string", "some other string"); 这个方法。它会帮你构建元组,并且会为你创建PyStrings。想了解更多,可以查看这个链接:http://docs.python.org/c-api/arg.html#Py_BuildValue