使用C扩展python,返回numpy数组会产生垃圾

我正在包装一个C文件,所以我可以在python中使用它. C函数的输出是双精度数组.我希望这是python中的一个numpy数组.我得到了垃圾.这是一个生成错误的示例.

首先,C文件(专注于最后一个函数定义,其他一切应该没问题):

#include <Python.h>
#include <numpy/arrayobject.h>
#include <stdio.h>

static char module_docstring[] =
    "docstring";

static char error_docstring[] =
        "generate the error";

static PyObject *_aux_error(PyObject *self, PyObject *args);

static PyMethodDef module_methods[] = {
        {"error", _aux_error, METH_VARARGS, error_docstring},
        {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC init_tmp(void) {

    PyObject *m = Py_InitModule3("_tmp", module_methods, module_docstring);
    if (m == NULL)
        return;

    /* Load `numpy` functionality. */
    import_array();
}

static PyObject *_aux_error(PyObject *self ,PyObject *args) {

    double vector[2] = {1.0 , 2.0};

    npy_intp dims[1] = { 2 };

    PyObject *ret  = PyArray_SimpleNewFromData(1, dims, (int)NPY_FLOAT , vector );
    return ret;
}

编译顺利(根据我的理解 – 我使用了编译所有内容的python脚本).

在python中,我运行以下脚本来测试我的新模块:

try:
    import _tmp
    res = _tmp.error()
    print(res)
except:
    print("fail")

我在屏幕上看到的结果是垃圾.我尝试用(int)NPY_FLOAT32,(int)NPY_FLOAT64,(int)NPY_DOUBLE替换(int)NPY_FLOAT,我仍然得到垃圾.
我正在使用python2.7.

谢谢!!!

编辑:按照下面的答案,我将最后一个功能更改为:

static PyObject *_aux_error(PyObject *self, PyObject *args) {


    double *vector = calloc(2, sizeof(double));
    vector[0] = 1.0;
    vector[1] = 2.0;


    npy_intp *dims = calloc(1 , sizeof(npy_intp));
    dims[1] = 2;


    PyObject *ret  = PyArray_SimpleNewFromData(1, dims, (int)NPY_FLOAT , &vector );
    return ret;
}

现在python显示一个空数组.

最佳答案
尝试改变这个:

static PyObject *_aux_error(PyObject *self) {

对此:

static PyObject *_aux_error(PyObject *self, PyObject *args) {

Python将传递args参数,即使您没有使用它定义函数.

您的代码仍然存在根本问题.您已使用堆栈上的数组vector创建了一个numpy数组.当_aux_error返回时,该内存将被回收并可能被重用.

您可以使用PyArray_SimpleNew()创建数组以分配numpy数组,然后将vector复制到数组的数据:

static PyObject *_aux_error(PyObject *self, PyObject *args)
{
    double vector[2] = {1.0 , 2.0};
    npy_intp dims[1] = {2};

    PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE);
    memcpy(PyArray_DATA(ret), vector, sizeof(vector));
    return ret;
}

请注意,我将类型更改为NPY_DOUBLE; NPY_FLOAT是32位浮点类型.

在评论中,您询问了如何在_aux_error中动态分配内存.以下是可能有用的示例的变体.数组的长度仍然在dims中进行硬编码,因此它并不完全通用,但它可能足以解决注释中的问题.

static PyObject *_aux_error(PyObject *self, PyObject *args)
{
    double *vector;
    npy_intp dims[1] = {5};
    npy_intp k;

    PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE);
    vector = (double *) PyArray_DATA(ret);
    /*
     *  NOTE: Treating PyArray_DATA(ret) as if it were a contiguous one-dimensional C
     *  array is safe, because we just created it with PyArray_SimpleNew, so we know
     *  that it is, in fact, a one-dimensional contiguous array.
     */
    for (k = 0; k < dims[0]; ++k) {
        vector[k] = 1.0 + k;
    }
    return ret;
}

转载注明原文:使用C扩展python,返回numpy数组会产生垃圾 - 代码日志