如何为在C中分配的numpy数组注册析构函数?

8
我想在C/C++中为numpy数组分配数字,并将它们作为numpy数组传递给Python。这可以使用PyArray_SimpleNewFromData完成。
问题在于,我还想注册一个函数,在numpy数组引用计数器达到零时从Python中调用该函数,并在C端调用一些析构语义...这是我所需要的伪代码示例:
 float* arr; PyObject* np_arr; void (*destructor)(float* arr);
 // ... C-allocate array on arr, ...
 // ...
 // ... initialize destructor with some suitable value, and then:
 np_arr = /* ... create the array to wrap arr, 
             and to use destructor on some meaningful way ... */

有没有简单的方法可以这样做?


没有一个简单的方法,但我认为这个URL会回答你的问题http://blog.enthought.com/python/numpy-arrays-with-pre-allocated-memory/。 - James Hurford
1个回答

9

这个想法是创建一个Python对象,它知道如何在销毁时释放内存,并将其作为返回的C分配的numpy数组的基础。这听起来很棘手,但可以通过Python中的一些东西轻松实现,称为capsules。让我举个例子,

假设您有以下代码,

PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);

arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
return arr;

这里存在一个明显的内存泄漏问题,因为在删除arr之前无法释放数据,正如此处红色警告框中所述。另一方面,修复这个问题很容易。定义一个函数,基本上是一个析构函数,它知道如何进行垃圾回收。
void capsule_cleanup(PyObject *capsule) {
    void *memory = PyCapsule_GetPointer(capsule, NULL);
    // Use your specific gc implementation in place of free if you have to
    free(memory);
}

现在,您可以将代码改为以下形式:
PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);

arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
PyObject *capsule = PyCapsule_New(data, NULL, capsule_cleanup);
// NULL can be a string but use the same string while calling PyCapsule_GetPointer inside capsule_cleanup
PyArray_SetBaseObject((PyArrayObject *) arr, capsule);
return arr;

不需要使用Py_DECREF来释放胶囊。函数PyArray_SetBaseObject会窃取引用。
希望这可以帮到你!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接