Search code examples
pythonpython-c-apipython-extensions

INCREF needed when returning argument from Python C Extension function?


This question is pretty simple but will help cement my understanding. I know that arguments to C extension functions are guaranteed to be live references for the duration of the C code (unless manually DECREFed). However, if I have a C extension code that returns a PyObject* that was present in its argument list, do I need to INCREF the argument before returning it? I.e., which of the following two is correct:

static PyObject return_item(PyObject *self, PyObject *item)
{
    // manipulate item
    return item;
}

or

static PyObject return_item(PyObject *self, PyObject *item)
{
    // manipulate item
    Py_INCREF(item);
    return item;
}

Based on https://docs.python.org/3/extending/extending.html#ownership-rules, which says

The object reference returned from a C function that is called from Python must be an owned reference — ownership is transferred from the function to its caller.

and Returning objects to Python from C I assume it's the latter (INCREFing is the way to go) but I want to be sure.


Solution

  • If someone is calling the return_item function from Python, they might do this:

    something = Something()
    something_else = return_item(something)
    del something
    

    If return_item did not return the argument which was passed in, but something else, you would expect that at this point the something which was passed in should be freed from memory, because its reference count falls to zero.

    If you don't Py_INCREF and return the same object, that will still happen - the object's reference count will fall to 0 and you will have an invalid object in something_else.

    TL;DR: Yes, you should Py_INCREF, because you created another reference to that object by returning it from the function.