numpy array C api

J’ai une fonction C ++ renvoyant un std :: vector et je veux l’utiliser en python, donc j’utilise l’api C numpy:

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

Voici comment je l’appelle de 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 

Qu’est-ce qui se passe est la suivante: La première impression est ok, les valeurs sont correctes. Mais quand je complote a ils ne sont pas; dans la deuxième impression, je vois des valeurs très étranges telles que 1E-308 1E-308 ... ou 0 0 0 ... tant que mémoire non initialisée. Je ne comprends pas pourquoi la première impression est correcte.

Solution partielle (ne fonctionne pas):

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

Votre object std::vector semble être local à cette fonction. PyArray_SimpleNewFromData ne copie pas les données que vous lui transmettez. Cela ne fait que garder un pointeur. Donc, une fois que votre fonction py_integrate est revenue, le vecteur est désalloué. L’impression fonctionne pour la première fois car rien n’a encore été écrit sur la mémoire libérée, mais au moment où vous passez à l’impression suivante, quelque chose d’autre a utilisé cette mémoire, ce qui rend les valeurs différentes.

Vous devez créer un tableau NumPy qui possède son propre espace de stockage, puis y copier les données.

Sinon, allouez votre vecteur sur le tas. Puis stockez un pointeur dans un CObject . Fournissez un destructeur qui supprime le vecteur. Examinez ensuite le type PyArrayObject de niveau C. Il a un membre PyObject * appelé base . Rangez votre CObject ici. Ensuite, lorsque le tableau NumPy est nettoyé, le décompte de références sur cet object de base est décrémenté. Si vous n’en avez pas pris une copie ailleurs, votre vecteur sera supprimé grâce au destructeur que vous avez fourni.

Fixateur supérieur

Vous avez oublié de créer le PyArray. Essaye ça:

(Vous n’avez pas DeleteVector , je ne peux donc qu’espérer que c’est correct)

 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; 

Remarque: je ne suis pas un programmeur C ++, je ne peux donc que supposer que &((*vector)[0]) fonctionne comme prévu avec un pointeur sur un vecteur. Je sais que le vecteur réaffecte sa zone de stockage si vous le cultivez. Par conséquent, n’augmentez pas sa taille après avoir obtenu ce pointeur, sinon il ne sera plus valide.

Vous devrez faire une copie du vecteur, car celui-ci sera hors de scope et la mémoire ne sera plus utilisable au moment où vous en aurez besoin en Python (comme indiqué par kwatford).

Une façon de créer le tableau Numpy dont vous avez besoin (en copiant les données) est la suivante:

 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());