Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DECREF'ing after a call to PyArray_DATA

Tags:

I'm writing a Python extension in C. My function takes a list of Numpy arrays (that contain integers) as a parameter. I go through the list, get each array, increase the reference, get the C pointers to the array and then decrease the reference.

if (!PyArg_ParseTuple(args, "O", &list))
    return NULL;

long nb_arrays = PyList_Size(list);

arrays = (int **) malloc(nb_arrays * sizeof(int *));

for (i = 0; i < nb_arrays; i++)
{
    PyArrayObject *array = (PyArrayObject *) PyList_GetItem(list, i);
    Py_INCREF(array);

    arrays[i] = (int *) PyArray_DATA(array);

    Py_DECREF(array);
}

After this loop, I'm using the pointers to do my calculations. Is it correct or must I wait for the end of the function to decrease the reference counts?

like image 620
Mark Morrisson Avatar asked Jun 20 '16 09:06

Mark Morrisson


1 Answers

PyArray_DATA has no effect on the reference count of the array it is applied to. Furthermore, when the list that was passed to your function was created, the reference count of each of the arrays in it was increased by one. So while they don't hurt much, those Py_INCREF and Py_DECREF are completely unnecessary, you can get rid of both of them.

You typically have to Py_INCREF an object when you are going to pass it to a function that steals the reference (i.e. takes ownership of it and assumes the responsibility of decreasing the count when it is done with needing it).

You typically have to Py_DECREF any temporary objects you have created inside a function, that are not part of your returns, and that are not needed by any of the returns.

You rarely (if ever) have to first Py_INCREF something to later Py_DECREF it. You can probably write some messed up multi-threaded code releasing the GIL that makes this parragraph not true, but in general everything passed to your function was part of a tuple (if a positional argument) or a dictionary (if a keyword argument), so it had its reference count increased when the call was made. That tuple and dictionary will not be destroyed until your function returns, so it is safe to assume that all items passed to you will not be garbage collected midway through your function, i.e. you are borrowing that reference, hence there is no need to explicitly increase the reference count just to access the objects.

like image 176
Jaime Avatar answered Sep 28 '22 01:09

Jaime