扩展蟒蛇与C,返回numpy的数组给垃圾 [英] Extend python with C, return numpy array gives garbage

查看:198
本文介绍了扩展蟒蛇与C,返回numpy的数组给垃圾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我环绕C文件,所以我可以在Python中使用它。 C函数的输出是双打的数组。我希望这是一个Python numpy的数组。我得到的垃圾。下面是生成错误的例子。

I am wrapping a C file so I can use it in python. The output of the C function is an array of doubles. I want this to be a numpy array in python. I get garbage. Here's an example that generates the error.

首先,C文件(集中在最后一个函数的定义,一切应该是OK):

First, the C file (focus on the last function definition, everything else should be 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脚本编译一切)

Compilation goes OK (from what I understand - I used a python script that compiles everything).

在蟒蛇,我运行下面的脚本来测试我的新模块:

In python, I run the following script to test my new module:

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

我在屏幕上看到的结果是垃圾。我试图取代(INT)NPY_FLOAT (INT)NPY_FLOAT32,(INT)NPY_FLOAT64,(INT)NPY_DOUBLE 和我仍然得到垃圾。
我使用python2.7。

The result I see on the screen is garbage. I tried substituting (int)NPY_FLOAT with (int)NPY_FLOAT32, (int)NPY_FLOAT64, (int)NPY_DOUBLE and I still get garbage. I am using python2.7.

谢谢!

修改:按照下面的答案,我改变了最后一个功能:

EDIT: following the answer below, I changed the last function to:

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

现在蟒蛇显示一个空数组。

Now python shows an empty array.

推荐答案

尝试改变这一点:

static PyObject *_aux_error(PyObject *self) {

这样:

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

Python将通过 ARGS 的说法,即使你不使用它定义的功能。

Python will pass the args argument, even if you don't define your function with it.

有仍然与code的一个根本问题。你已经创建使用数组numpy的阵列,矢量,也就是在堆栈中。当 _aux_error 的回报,内存被回收,并可能被重用。

There's still a fundamental problem with your code. You have created a numpy array using an array, vector, that is on the stack. When _aux_error returns, that memory is reclaimed and might be reused.

您可以用创建数组 PyArray_SimpleNew()来分配numpy的数组,然后复制矢量来的阵列的数据:

You could create the array using PyArray_SimpleNew() to allocate the numpy array, and then copy vector to the array's data:

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位浮点类型。

Note that I changed the type to NPY_DOUBLE; NPY_FLOAT is the 32 bit floating point type.

在一个评论,你问动态地分配在 _aux_error 的内存。下面是可能有用的示例的变化。数组的长度仍然是变暗硬$ C $光盘,所以它是不完全一般,但它可能足以从注释解决的问题。

In a comment, you asked about dynamically allocating the memory in _aux_error. Here's a variation of the example that might be useful. The length of the array is still hardcoded in dims, so it isn't completely general, but it might be enough to address the question from the comments.

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,返回numpy的数组给垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆