Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C扩展python,返回numpy数组_Python_C_Python 2.7_Numpy_Wrapper - Fatal编程技术网

用C扩展python,返回numpy数组

用C扩展python,返回numpy数组,python,c,python-2.7,numpy,wrapper,Python,C,Python 2.7,Numpy,Wrapper,我正在包装一个C文件,以便在python中使用它。C函数的输出是一个双精度数组。我希望这是python中的numpy数组。我有垃圾。下面是一个生成错误的示例 首先是C文件(关注最后一个函数定义,其他一切都应该正常): 我在屏幕上看到的结果是垃圾。我试着用(int)NPY\u FLOAT32,(int)NPY\u FLOAT64,(int)NPY\u DOUBLE替换(int)NPY\u FLOAT,但我仍然收到垃圾。 我正在使用python2.7 谢谢 编辑:根据下面的答案,我将最后一个函数更改

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

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

我在屏幕上看到的结果是垃圾。我试着用
(int)NPY\u FLOAT32,(int)NPY\u FLOAT64,(int)NPY\u DOUBLE
替换
(int)NPY\u 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数组。当
\u aux\u error
返回时,该内存将被回收并可能被重用

您可以使用
PyArray\u 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位浮点类型


在评论中,您询问了在
\u aux\u 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;
}
静态PyObject*\u辅助错误(PyObject*self,PyObject*args)
{
双*向量;
npy_intp dims[1]={5};
npy_intp k;
PyObject*ret=PyArray\u SimpleNew(1,dims,NPY\u DOUBLE);
向量=(双*)PyArray_数据(ret);
/*
*注意:将PyArray_数据(ret)视为一个连续的一维C
*数组是安全的,因为我们刚刚用PyArray\u SimpleNew创建了它,所以我们知道
*事实上,它是一个一维连续数组。
*/
对于(k=0;k
这是我的完整解决方案,供您娱乐。复制、粘贴和修改。显然,我面临的问题比上面的问题要复杂一些。我用了一些

我的代码的目标是返回一个协方差向量(不管它是什么)。我有一个名为
aux.C
的C文件,它返回一个新分配的数组:

#include "aux.h"
#include <math.h>
#include <stdlib.h>
double *covVec(double *X, double *x, int nvecs, int veclen) {


    double r = 1.3;
    double d = 1.0;

    double result;
    double dist;
    int n;

    double *k;
    k = malloc(nvecs * sizeof(double));

    int row;
    for( row = 0 ; row < nvecs ; row++) {

        result = 0.0;
        for (n = 0; n < veclen; n++) {
                dist = x[n] - X[row*veclen + n];
                result += dist * dist;
        }

        result = d*exp(  -result/(2.0*r*r)  );
        k[row] = result;
    }
    return k;
}
要将其包装到python中,我有
\u aux.c

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

static char module_docstring[] =
    "This module provides an interface for calculating covariance using C.";

static char cov_vec_docstring[] =
    "Calculate the covariances between a vector and a list of vectors.";

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

static PyMethodDef module_methods[] = {
        {"cov_vec", _aux_covVec, METH_VARARGS, cov_vec_docstring},
        {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC init_aux(void) {

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

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


static PyObject *_aux_covVec(PyObject *self, PyObject *args)
{
    PyObject *X_obj, *x_obj;

    /* Parse the input tuple */
    if (!PyArg_ParseTuple(args, "OO", &X_obj, &x_obj ))
        return NULL;

    /* Interpret the input objects as numpy arrays. */
    PyObject *X_array = PyArray_FROM_OTF(X_obj, NPY_DOUBLE, NPY_IN_ARRAY);
    PyObject *x_array = PyArray_FROM_OTF(x_obj, NPY_DOUBLE, NPY_IN_ARRAY);


    /* If that didn't work, throw an exception. */
    if (X_array == NULL || x_array == NULL ) {
        Py_XDECREF(X_array);
        Py_XDECREF(x_array);
        return NULL;
    }

    /* What are the dimensions? */
    int nvecs  = (int)PyArray_DIM(X_array, 0);
    int veclen = (int)PyArray_DIM(X_array, 1);
    int xlen   = (int)PyArray_DIM(x_array, 0);

    /* Get pointers to the data as C-types. */
    double *X    = (double*)PyArray_DATA(X_array);
    double *x    = (double*)PyArray_DATA(x_array);


    /* Call the external C function to compute the covariance. */
    double *k = covVec(X, x, nvecs, veclen);



    if ( veclen !=  xlen ) {
        PyErr_SetString(PyExc_RuntimeError,
                                "Dimensions don't match!!");
        return NULL;
    }

    /* Clean up. */
    Py_DECREF(X_array);
    Py_DECREF(x_array);

    int i;
    for(i = 0 ; i < nvecs ; i++) {
        printf("k[%d]   = %f\n",i,k[i]);
        if (k[i] < 0.0) {
            PyErr_SetString(PyExc_RuntimeError,
                        "Covariance should be positive but it isn't.");
            return NULL;
        }
    }

    npy_intp dims[1] = {nvecs};

    PyObject *ret = PyArray_SimpleNew(1, dims, NPY_DOUBLE);
    memcpy(PyArray_DATA(ret), k, nvecs*sizeof(double));
    free(k);

    return ret;
}
我使用
python2.7 setup\u cov.py build\u ext--inplace
从命令行编译。 然后运行以下python测试文件:

import numpy as np
import _aux as a

nvecs  = 6
veclen = 9
X= []
for _ in range(nvecs):
    X.append(np.random.normal(size= veclen))
X = np.asarray(X)

x = np.random.normal(size=veclen)
k = a.cov_vec(X,x)
print(k)

Warren的解决方案似乎是可行的,尽管对我来说释放C数组内存块会导致编译错误。我使用了memcopy技巧在下面的最小函数中工作(通过指针将1D C数组复制到numpy),为简单起见,它不带任何参数,并且应该让读者了解如何将其应用到C数组而不是向量:

static PyObject *_cmod_test(PyObject *self, PyObject *args)
    {
    double f[5] = {0,1,2,3,4};
    int d[1] = {5};
    PyObject *c = PyArray_FromDims(1,d,NPY_DOUBLE);
    memcpy(PyArray_DATA(c), f, 5*sizeof(double));
    return c;    
    };
launch.py脚本很简单

import _cmod
_cmod.test()
不要忘记声明函数

#include <Python.h>
#include <numpy/arrayobject.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
static PyObject *_cmod_test(PyObject *self, PyObject *args);

我还推荐Dan Foreman Mackay关于python C API的博客。

感谢您的输入,但这没有帮助。这个例子不应该通过删除*args而不给函数任何变量而变得更简单吗?不——python解释器不知道您已经用非标准签名定义了
\aux\u error
。它将用两个C参数调用。请注意,我更新了我的答案,并对您的示例中的一个基本问题进行了注释。维度由数组构造函数复制,但数组数据不是。如果在
\u aux\u error
中有类似
vector=malloc(…)
,然后用一些计算值填充向量,然后调用
PyObject*ret=PyArray\u SimpleNew(…);memcpy(PyArray_DATA(ret)、vector、sizeof(vector)),那么是的,您应该在返回之前释放
vector
。但是如果知道数组的长度,可以调用
PyObject*ret=PyArray\u SimpleNew(…)
,然后使用
double*vector=PyArray\u DATA(ret)
,并填写
vector
。这样你就不需要malloc任何内存了——因为
PyArray\u SimpleNew
为你做了这件事——你也不会释放
vector
。你编辑的调用应该是
PyArray\u SimpleNewFromData(1,dims,NPY\u DOUBLE,vector)
。它也不是这样工作的吗?
dims[1]=2
是一个索引错误
import numpy as np
import _aux as a

nvecs  = 6
veclen = 9
X= []
for _ in range(nvecs):
    X.append(np.random.normal(size= veclen))
X = np.asarray(X)

x = np.random.normal(size=veclen)
k = a.cov_vec(X,x)
print(k)
static PyObject *_cmod_test(PyObject *self, PyObject *args)
    {
    double f[5] = {0,1,2,3,4};
    int d[1] = {5};
    PyObject *c = PyArray_FromDims(1,d,NPY_DOUBLE);
    memcpy(PyArray_DATA(c), f, 5*sizeof(double));
    return c;    
    };
import _cmod
_cmod.test()
#include <Python.h>
#include <numpy/arrayobject.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
static PyObject *_cmod_test(PyObject *self, PyObject *args);
static PyObject *_cmod_test(PyObject *self, PyObject *args)
    {
    double f[5] = {0,1,2,3,4};
    npy_intp dims[1] = {5};
    PyObject *c = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE ,f);
    PyArray_ENABLEFLAGS(c, NPY_ARRAY_OWNDATA);
    return c;
    };