Destroying a PyCapsule Object

According to the documentation , the third argument to PyCapsule_New() can specify a destructor, which I believe should be called when the capsule is destroyed.

 void mapDestroy(PyObject *capsule) { lash_map_simple_t *map; fprintf(stderr, "Entered destructor\n"); map = (lash_map_simple_t*)PyCapsule_GetPointer(capsule, "MAP_C_API"); if (map == NULL) return; fprintf(stderr, "Destroying map %p\n", map); lashMapSimpleFree(map); free(map); } static PyObject * mapSimpleInit_func(PyObject *self, PyObject *args) { unsigned int w; unsigned int h; PyObject *pymap; lash_map_simple_t *map = (lash_map_simple_t*)malloc(sizeof(lash_map_simple_t)); pymap = PyCapsule_New((void *)map, "MAP_C_API", mapDestroy); if (!PyArg_ParseTuple(args, "II", &w, &h)) return NULL; lashMapSimpleInit(map, &w, &h); return Py_BuildValue("O", pymap); } 

However, when I instantiate an object and delete it or exit the Python console, the destructor does not seem to be called:

 >>> a = mapSimpleInit(10,20) >>> a <capsule object "MAP_C_API" at 0x7fcf4959f930> >>> del(a) >>> a = mapSimpleInit(10,20) >>> a <capsule object "MAP_C_API" at 0x7fcf495186f0> >>> quit() la sh@CANTANDO ~/programming/src/liblashgame $ 

I assume that it has something to Py_BuildValue() with Py_BuildValue() , returning a new link to the "capsule", which when deleted does not affect the original. Anyway, how can I ensure that the object is properly destroyed?

Using Python 3.4.3 [GCC 4.8.4] (on Linux)

+5
source share
2 answers

There is a leak reference in the above code: pymap = PyCapsule_New() returns a new object (its refcount is 1), but Py_BuildValue("O", pymap) creates a new link to the same object, and its refcount is now 2.

Just return pymap; .

+1
source

Py_BuildValue("O", thingy) will simply increase the thingy for thingy and return it - the docs say that it returns a "new link", but this is not entirely true when you pass an existing PyObject* .

If these your functions are the ones in your question, that is, they are all defined in the same translation unit, the destructor function should probably be declared static (therefore, its full signature will be static void mapDestroy(PyObject* capsule); ) so that the Python API can correctly search for addresses when it is time to call the destructor.

... You do not need to use the static function if the address of the destructor in memory is valid. For example, Ive successfully used the non-capturing C ++ lambda as a destructor , since non-capturing C ++ lambdas can be converted to function pointers; if you want to use a different method of receiving and passing a function pointer to your capsule destructor, which works best for you, you should definitely go for it.

0
source

All Articles