потеряно на 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 2

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)

Надеюсь, что это помогает. Основная подсказка находится в документах, если там написано: "Крадет ссылку", то функция в основном берет на себя ответственность, если она говорит "новая ссылка", то она сделала ИНКРЕФ для вас, если ничего не сказано, она, вероятно, делает ИНКРЕФ и ДЕКРЕФ пару по мере необходимости.

PyList_Append() не" крадет " ссылку, поэтому, если вы не собираетесь использовать добавленное значение после, уменьшите его.

Кроме того, не забудьте вернуть PyObject* из функции, иначе система подумает, что произошло исключение.