python - 用 C 扩展 python,返回 numpy 数组给出垃圾

标签 python c python-2.7 numpy wrapper

我正在包装一个 C 文件,以便我可以在 python 中使用它。 C 函数的输出是 double 组。我希望这是 python 中的一个 numpy 数组。我得到垃圾。下面是生成错误的示例。

首先是C文件(关注最后一个函数定义,其他都应该OK):

#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_DOUBLENPY_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;
}

关于python - 用 C 扩展 python,返回 numpy 数组给出垃圾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27829946/

相关文章:

python - 将任意长度的位置列表 [4, 1, 2] 转换为嵌套列表的索引

python : Process calling GRPC server gets stuck and terminates unexpectedly

python - 带有可选参数的 ArgumentParser(在互斥组中)

c - 链接列表添加功能未按预期工作

c++ - 为什么 gettimeofday() 间隔偶尔为负数?

c - 在 C 中为自引用结构分配内存

Django 获取内联表单管理员中的实例

python - 在代码中兼容地使用字符串和类字节对象以在 Python 2 和 3 中运行

python - 如何在每个维度上调整体积图像的大小或形状?

python - 在 python 脚本上导入某些包时出现错误