потеряно на PY DECREF / INCREF при обработке Pylist Append в Python C extension
Я теряюсь на Py_DECREF/INCREF при обработке PyList_Append. Может ли кто-нибудь прокомментировать следующие коды?
PyObject * bugmaybe(PyObject *self, PyObject *args)
{
PyObject * trio=PyList_New(0);
PyObject * trio_tmp;
PyObject * otmp = PyFloat_FromDouble(1.2);
PyList_Append(trio_tmp,otmp);
//Py_DECREF(otmp);
otmp = PyFloat_FromDouble(2.3);
PyList_Append(trio_tmp,otmp);
//Py_DECREF(otmp);
PyList_Append(trio,trio_tmp);
Py_INCREF(trio_tmp);
}
2 ответа:
Если вы знаете размер списка заранее его обычно быстрее, чтобы создать список с правильным размером и использовать
PyList_SetItem()
.Ваш код просто неверен,
trio_tmp
неинициализирован.Попробуйте вот что:
PyObject * bugmaybe(PyObject *self, PyObject *args) { PyObject * trio=PyList_New(3); PyObject * otmp = PyFloat_FromDouble(1.2); PyList_SetItem(trio,0,otmp); otmp = PyFloat_FromDouble(2.3); PyList_SetItem(trio,1,otmp); PyList_Append(trio,2, PyList_New(0)); return trio; }
Если вы действительно хотите использовать
PyList_Append
, ваш код был в основном в порядке, просто не хватало инициализации дляtrio_tmp
и лишнего Py_INCREF в конце.PyObject * bugmaybe(PyObject *self, PyObject *args) { PyObject * trio=PyList_New(0); // trio has refcount 1 PyObject * trio_tmp = PyList_New(0); // trio_tmp has recount 1 PyObject * otmp = PyFloat_FromDouble(1.2); // otmp has recount 1 PyList_Append(trio_tmp,otmp); // Append does not steal a reference, so otmp refcoun = 2 Py_DECREF(otmp); // otmp refcount = 1, but stored in the list so the pointer var // can be reused otmp = PyFloat_FromDouble(2.3); PyList_Append(trio_tmp,otmp); Py_DECREF(otmp); // as above PyList_Append(trio,trio_tmp); // decrement refcount for trio_tmp, as it has recount 2 now. Py_DECREF(trio_tmp); return trio; }
Приведенный выше код будет эквивалентен:
trio = [] trio_tmp = [] otmp = 1.2 trio_tmp.append(otmp) otmp = 2.3 trio_tmp.append(otmp) trio.append(trio_tmp)
Надеюсь, что это помогает. Основная подсказка находится в документах, если там написано: "Крадет ссылку", то функция в основном берет на себя ответственность, если она говорит "новая ссылка", то она сделала ИНКРЕФ для вас, если ничего не сказано, она, вероятно, делает ИНКРЕФ и ДЕКРЕФ пару по мере необходимости.