Подсчет ссылок в расширении Python C
Я пишу свое первое расширение C на Python и смущаюсь о моих подсчетах ссылок. Вот что я пытаюсь сделать.
Я заполняю dict в цикле for:
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 refcnt is 2. PyString_FromString sets it to 1 and
PyDict_SetItem INCREF it. Ditto for pair since PyDict_SetItem also INCREF's
the value.
*/
Py_DECREF(pair);
/* pair 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;
Я правильно ли пересчитал счетчик ссылок? В документах API C специально рекомендуется использовать PyObject_FromXXX
функции как аргументы для PyTuple_SetItem
или PyList_SetItem
, потому что они "украдут" ссылки.
Не документировано, если 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
Если вы посмотрите на исходный код CPython (Objects/tupleobject.c) для PyTuple_Pack, вы увидите, что он действительно увеличивает счетчик ссылок на каждый упакованный объект. Если вы вместо этого выполняете PyTuple_New, а затем вызовы PyTuple_SetItem, вам не нужно будет уменьшать количество ссылок, поскольку SetItem крадет ссылки.
Наконец, вы можете просто хотеть использовать Py_BuildValue ( "(ss)", "некоторая строка", "некоторая другая строка" );
Он построит ваш кортеж для вас, и он создаст PyStrings для вас:
http://docs.python.org/c-api/arg.html#Py_BuildValue