Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lost on Py_DECREF/INCREF when handling PyList_Append in Python C extension

I am lost on Py_DECREF/INCREF when handling PyList_Append. Can anybody have comments on the following codes?

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);
}
like image 852
Hailiang Zhang Avatar asked Jun 07 '26 19:06

Hailiang Zhang


1 Answers

If you know the size of the list upfront its usually faster to create the list with the right size and use PyList_SetItem().

Your code is simply wrong, trio_tmpis uninitialized.

Try this:

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;
}

If you really want to use PyList_Append, your code was mostly ok, just missing the initialization for trio_tmpand the superfluous Py_INCREF at the end.

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;
}

The code above would be equivalent to:

 trio = []
 trio_tmp = []
 otmp = 1.2
 trio_tmp.append(otmp)
 otmp = 2.3
 trio_tmp.append(otmp)
 trio.append(trio_tmp)

Hope it helps. The main hint is in the docs, if it says 'Steals a reference' then the function basically takes ownership, if it says 'New Reference' then it did an INCREF for you, if nothing is said it probably does an INCREF and DECREF pair as needed.

like image 169
schlenk Avatar answered Jun 09 '26 07:06

schlenk