numpy的阵列C API [英] numpy array C api

查看:181
本文介绍了numpy的阵列C API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C ++函数返回一个std :: vector和我想在Python中使用它,所以我使用的是C numpy的API:

 静态的PyObject *
py_integrate(*的PyObject自我,*的PyObject参数){
    ...
    的std ::矢量<&双GT;积分;
    cpp_function(积分); //这改变积分
    npy_intp大小= {integral.size()};
    的PyObject *总分= PyArray_SimpleNewFromData(1,&安培;大小,NPY_DOUBLE,及(积分[0]));
    返回的;
}

下面就是我把它从蟒蛇:

 进口matplotlib.pyplot如PLT一个= py_integrate(参数)
打印一
图= plt.figure()
AX = fig.add_subplot(111)
ax.plot(一)
打印一

什么情况是:第一打印就可以了,值是正确的。但是,当我绘制 A 他们都没有;在第二次印刷我看像 1E-308 1E-308 ... 0 0 0 ... 作为一个未初始化的内存。我不明白为什么第一次印刷就可以了。

部分解决方案(不工作):

 静态无效DeleteVector(无效* PTR)
{
    性病::法院LT&;< 删除<<的std :: ENDL;
    矢量* V =的static_cast<的std ::矢量<&双GT; * GT(PTR);
    删除伏;
    返回;
}静态的PyObject *
cppfunction(*的PyObject自我,*的PyObject参数)
{
    的std ::矢量<&双GT; *向量=新的std ::矢量<&双GT;();
    病媒>的push_back(1);
    *的PyObject = py_integral PyCObject_FromVoidPtr(矢量,DeleteVector);
    npy_intp大小= {病媒>大小()};
    PyArrayObject *总分;
    ((PyArrayObject *)出) - GT;基地= py_integral;
    回报(*的PyObject)(出);
}


解决方案

的std ::矢量对象看起来是局部的功能。 PyArray_SimpleNewFromData 不会使你传递给它的数据的副本。它只是让一个指针。所以,一旦你的py_integrate函数返回时,矢量被释放。打印的作品第一次因为没有撰写了释放的内存还没有,但你到下一个打印的时候,别的已经使用的内存,导致这些值是不同的。

您需要做一个numpy的阵列拥有自己的存储空间,然后将数据复制到它。

另外,在堆上分配您的载体。然后一个指向其存储在 CObject的。提供删除该载体的析构函数。然后,看看C级<一个href=\"http://docs.scipy.org/doc/numpy/reference/c-api.types-and-structures.html#PyArrayObject\">PyArrayObject类型。它有一个的PyObject * 成员名为。存储你的的CObject 那里。然后是垃圾收集numpy的阵列时,该基础对象的引用计数将递减,假设你没有采取它的副本在其他地方,你的载体将被删除感谢你们提供的析构函数。

固定器,上

您忘了实际创建PyArray。试试这个:

(你没有张贴 DeleteVector ,所以我只能希望这是正确的)

 的std ::矢量&lt;&双GT; *向量=新的std ::矢量&lt;&双GT;();
病媒&GT;的push_back(1);
*的PyObject = py_integral PyCObject_FromVoidPtr(矢量,DeleteVector);
npy_intp大小= {病媒&GT;大小()};
的PyObject *总分= PyArray_SimpleNewFromData(1,&安培;大小,NPY_DOUBLE,及((*矢量)[0]));
((PyArrayObject *)出) - GT;基地= py_integral;
返回的;

请注意:我不是一个C ++程序员,所以我只能假设及((*向量)[0])按预期工作的指针的载体。我不知道,如果矢量你长大它重新分配其存储区域,因此让该指针后不增加它的大小,否则将不再有效。

I have a C++ function returning a std::vector and I want to use it in python, so I'm using the C numpy api:

static PyObject *
py_integrate(PyObject *self, PyObject *args){
    ...
    std::vector<double> integral;
    cpp_function(integral);  // This changes integral
    npy_intp size = {integral.size()};
    PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &(integral[0]));
    return out;
}

Here's how I call it from python:

import matplotlib.pyplot as plt

a = py_integrate(parameters)
print a
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(a)
print a

What happens is: The first print is ok, the values are correct. But when I plot a they are not; in the second print I see very strange values like 1E-308 1E-308 ... or 0 0 0 ... as an uninitialized memory. I don't understand why the first print is ok.

Partial solution (not working):

static void DeleteVector(void *ptr)
{
    std::cout << "Delete" << std::endl;
    vector * v = static_cast<std::vector<double> * >(ptr);
    delete v;
    return;
}

static PyObject *
cppfunction(PyObject *self, PyObject *args)
{
    std::vector<double> *vector = new std::vector<double>();
    vector->push_back(1.);
    PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
    npy_intp size = {vector->size()};
    PyArrayObject *out;
    ((PyArrayObject*) out)->base = py_integral;
    return (PyObject*)(out);
}

解决方案

Your std::vector object appears to be local to that function. PyArray_SimpleNewFromData does not make a copy of the data you pass it. It just keeps a pointer. So once your py_integrate function returns, the vector is deallocated. The print works the first time because nothing has written over the freed memory yet, but by the time you get to the next print, something else has used that memory, causing the values to be different.

You need to make a NumPy array that owns its own storage space and then copy the data into it.

Alternatively, allocate your vector on the heap. Then store a pointer to it in a CObject. Provide a destructor that deletes the vector. Then, take a look at the C-level PyArrayObject type. It has a PyObject * member called base. Store your CObject there. Then when the NumPy array is garbage collected, the reference count on this base object will be decremented, and assuming you haven't taken a copy of it elsewhere, your vector will be deleted thanks to the destructor you provided.

Fixer-upper

You forgot to actually create the PyArray. Try this:

(You didn't post DeleteVector, so I can only hope that it's right)

std::vector<double> *vector = new std::vector<double>();
vector->push_back(1.);
PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
npy_intp size = {vector->size()};
PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &((*vector)[0]));
((PyArrayObject*) out)->base = py_integral;
return out;

Note: I'm not a C++ programmer, so I can only assume that &((*vector)[0]) works as intended with a pointer to a vector. I do know that the vector reallocate its storage area if you grow it, so don't increase its size after getting that pointer or it won't be valid anymore.

这篇关于numpy的阵列C API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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