Python uses reference counting for memory management. Every Python object has a reference count tracking how many references point to it. When the count reaches zero, the object is deallocated.
Reference counting errors are the most common source of bugs in C extensions. Always track ownership carefully!
PyObject *item = PyList_GetItem(list, 0); // Borrowed referencePy_INCREF(item); // Convert to owned reference// Now we own a reference and must Py_DECREF later
Py_INCREF does nothing if the object is immortal (Python 3.12+), but you should still call it.
PyObject *result = PyLong_FromLong(42); // New reference// Use result...Py_DECREF(result); // Release our reference
Deallocation Side EffectsWhen an object’s refcount reaches zero, its __del__ method can execute arbitrary Python code. Ensure objects are in consistent state before calling Py_DECREF:
// WRONG:Py_DECREF(item); // May trigger code that uses listPyList_SetItem(list, 0, NULL);// RIGHT:PyObject *tmp = item;PyList_SetItem(list, 0, NULL); // Update data structure firstPy_DECREF(tmp); // Then decrement
Some functions return borrowed references - you don’t own them and shouldn’t decrement.Common borrowed reference functions:
PyList_GetItem() - Returns borrowed reference
PyTuple_GetItem() - Returns borrowed reference
PyDict_GetItem() - Returns borrowed reference
PyModule_GetDict() - Returns borrowed reference
Example:
PyObject *item = PyList_GetItem(list, 0); // Borrowed// Don't call Py_DECREF(item)!// If you need to store it:Py_INCREF(item); // Convert to owned referenceself->stored = item;
Some functions steal references - they take ownership without incrementing.Functions that steal:
PyList_SetItem() - Steals reference to item
PyTuple_SetItem() - Steals reference to item
PyModule_AddObject() - Steals reference to value
Example:
PyObject *list = PyList_New(1);PyObject *item = PyLong_FromLong(42); // New referencePyList_SetItem(list, 0, item); // Steals item reference// Don't call Py_DECREF(item)! List owns it nowreturn list;
If you need to keep a reference:
PyObject *item = PyLong_FromLong(42);Py_INCREF(item); // Extra reference for usPyList_SetItem(list, 0, item); // Steals one reference// We still own one reference to itemPy_DECREF(item);
// WRONG: Double-decrementPyObject *item = PyList_GetItem(list, 0);Py_DECREF(item); // Item was borrowed!// WRONG: Forgot to decrementPyObject *num = PyLong_FromLong(42);return num; // Should Py_DECREF first if not returning it// WRONG: Use after freePy_DECREF(obj);PyObject_Print(obj, stdout, 0); // obj might be freed!
Use Helper MacrosPrefer Py_CLEAR, Py_SETREF, Py_XSETREF over manual reference management: