gpt4 book ai didi

python - C 数组到 PyArray

转载 作者:太空狗 更新时间:2023-10-29 18:08:47 25 4
gpt4 key购买 nike

我在不使用 Cython 的情况下编写 Python C 扩展。

我想在 C 中分配一个 double 组,在一个内部函数(恰好在 Fortran 中)中使用它并返回它。我指出 C-Fortran 接口(interface)在 C 中工作得很好。

static PyObject *
Py_drecur(PyObject *self, PyObject *args)
{
// INPUT
int n;
int ipoly;
double al;
double be;

if (!PyArg_ParseTuple(args, "iidd", &n, &ipoly, &al, &be))
return NULL;

// OUTPUT
int nd = 1;
npy_intp dims[] = {n};
double a[n];
double b[n];
int ierr;

drecur_(n, ipoly, al, be, a, b, ierr);

// Create PyArray
PyObject* alpha = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, a);
PyObject* beta = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, b);

Py_INCREF(alpha);
Py_INCREF(beta);

return Py_BuildValue("OO", alpha, beta);
}

我调试了这段代码,当我尝试从 a 中创建 alpha 时,出现了段错误。到那里一切正常。函数 drecur_ 有效,如果删除它,我会遇到同样的问题。

现在,围绕 C 数据定义 PyArray 的标准方法是什么?我找到了文档,但没有很好的例子。另外,内存泄漏怎么办?在返回之前 INCREF 是否正确,以便保留 alpha 和 beta 的实例?当不再需要它们时如何重新分配?

编辑我终于用 NumPy cookbook 中的方法做对了.

static PyObject *
Py_drecur(PyObject *self, PyObject *args)
{
// INPUT
int n;
int ipoly;
double al;
double be;
double *a, *b;
PyArrayObject *alpha, *beta;

if (!PyArg_ParseTuple(args, "iidd", &n, &ipoly, &al, &be))
return NULL;

// OUTPUT
int nd = 1;
int dims[2];
dims[0] = n;
alpha = (PyArrayObject*) PyArray_FromDims(nd, dims, NPY_DOUBLE);
beta = (PyArrayObject*) PyArray_FromDims(nd, dims, NPY_DOUBLE);
a = pyvector_to_Carrayptrs(alpha);
b = pyvector_to_Carrayptrs(beta);
int ierr;

drecur_(n, ipoly, al, be, a, b, ierr);

return Py_BuildValue("OO", alpha, beta);
}

double *pyvector_to_Carrayptrs(PyArrayObject *arrayin) {
int n=arrayin->dimensions[0];
return (double *) arrayin->data; /* pointer to arrayin data as double */
}

请随时对此发表评论,感谢您的回答。

最佳答案

所以首先看起来可疑的是,您的数组 ab 在函数的本地范围内。这意味着返回后您将获得非法内存访问。

所以你应该声明数组

double *a = malloc(n*sizeof(double));

然后你需要确保内存稍后被你创建的对象释放。请参阅文档的引用:

PyObject PyArray_SimpleNewFromData(int nd, npy_intp dims, int typenum, void* data)

Sometimes, you want to wrap memory allocated elsewhere into an ndarray object for downstream use. This routine makes it straightforward to do that. The first three arguments are the same as in PyArray_SimpleNew, the final argument is a pointer to a block of contiguous memory that the ndarray should use as it’s data-buffer which will be interpreted in C-style contiguous fashion. A new reference to an ndarray is returned, but the ndarray will not own its data. When this ndarray is deallocated, the pointer will not be freed.

You should ensure that the provided memory is not freed while the returned array is in existence. The easiest way to handle this is if data comes from another reference-counted Python object. The reference count on this object should be increased after the pointer is passed in, and the base member of the returned ndarray should point to the Python object that owns the data. Then, when the ndarray is deallocated, the base-member will be DECREF’d appropriately. If you want the memory to be freed as soon as the ndarray is deallocated then simply set the OWNDATA flag on the returned ndarray.

对于您的第二个问题,Py_INCREF(alpha); 通常只有在您打算将引​​用保留在全局变量或类成员中时才是必需的。但是因为你只是包装了一个函数,所以你不必这样做。遗憾的是,函数 PyArray_SimpleNewFromData 可能没有将引用计数器设置为 1,如果是这种情况,您将不得不将其增加到 1。我希望这是可以理解的;)。

关于python - C 数组到 PyArray,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12582875/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com