numpy数组C api

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

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

这是我从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 

会发生什么:第一次打印没问题,值是正确的。 但是,当我绘制a他们不是; 在第二次打印中,我看到非常奇怪的值,如1E-308 1E-308 ...0 0 0 ...作为未初始化的内存。 我不明白为什么第一次打印没问题。

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

 static void DeleteVector(void *ptr) { std::cout << "Delete" << std::endl; vector * v = static_cast<std::vector * >(ptr); delete v; return; } static PyObject * cppfunction(PyObject *self, PyObject *args) { std::vector *vector = new std::vector(); 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); } 

您的std::vector对象似乎是该函数的本地对象。 PyArray_SimpleNewFromData不会复制您传递的数据。 它只是一个指针。 因此,一旦你的py_integrate函数返回,向量就会被释放。 打印工作是第一次,因为还没有写入释放的内存,但是当你进入下一个打印时,其他东西已经使用了那个内存,导致值不同。

您需要创建一个拥有自己的存储空间的NumPy数组,然后将数据复制到其中。

或者,在堆上分配矢量。 然后在CObject中存储指向它的指针。 提供删除向量的析构函数。 然后,看一下C级PyArrayObject类型。 它有一个名为basePyObject *成员。 将CObject存储在那里。 然后当NumPy数组被垃圾收集时,此基础对象的引用计数将递减,并假设您没有在其他地方获取它的副本,由于您提供的析构函数,您的向量将被删除。

固定器,上

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

(你没有发布DeleteVector ,所以我只能希望它是正确的)

 std::vector *vector = new std::vector(); 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; 

注意:我不是C ++程序员,所以我只能假设&((*vector)[0])按照指向向量的指针工作。 我知道如果你增长它,矢量会重新分配它的存储区域,所以在获得指针之后不要增加它的大小,否则它将不再有效。

您需要复制该向量,因为向量将超出范围,并且在Python中需要它时内存将不再可用(如kwatford所述)。

使您需要的Numpy数组(通过复制数据)的一种方法是:

 PyObject *out = nullptr; std::vector *vector = new std::vector(); vector->push_back(1.); npy_intp size = {vector.size()}; out = PyArray_SimpleNew(1, &size, NPY_DOUBLE); memcpy(PyArray_DATA((PyArrayObject *) out), vector.data(), vector.size());