Как получить доступ к массиву NumPy внутри PyCXX
Я хотел бы преобразовать массив numpy в какой-нибудь двойной * или stl вектор на стороне C++. Я на самом деле использую PyCXX для этого и не могу понять, как получить доступ к данным.
В настоящее время я могу получить доступ к буферу данных и вернуть его так:
Py::Object arrayShape(const Py::Tuple& args ){
Py::Object array= args[0];
return array.getAttr("data");
}
Но я не знаю, что с этим делать. Моя конечная цель - получить из него gsl_vector. В идеале мне не пришлось бы переписывать память. Но, может быть, это слишком много, чтобы спросить;)
1 ответ
Когда я ищу решение, и я могу найти только тех, кто публикует один и тот же вопрос без ответа, я публикую решение, как только обнаружу его. У тебя такой вопрос.
Во-первых, настоятельно рекомендуем использовать Cython в качестве клея и не двигаться дальше по этому опасному пути.
Таким образом, использование PyArray_FromAny даст вам представление о базовых данных, если это возможно, и копию в противном случае. Очень простой пример (сборка с -std= C++11, если вы честный и хороший человек, или VS2013, если вы пользователь Windows):
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <numpy/arrayobject.h>
Py::Object printNumpyArrayCxxFunction(const Py::Tuple& args)
{
if(args.length() != 1)
{
throw Py::RuntimeError("Exactly one argument required.");
}
PyObject* vector_{PyArray_FromAny(*args[0], PyArray_DescrFromType(NPY_DOUBLE), 1, 1, NPY_ARRAY_CARRAY_RO, nullptr)};
if(!vector_)
{
throw Py::ValueError("Failed to convert argument into a 1d numpy double (64-bit float) array.");
}
Py::Object vector(vector_, true);
PyArrayObject* vector_npy{reinterpret_cast<PyArrayObject*>(vector_)};
npy_intp vector_length{PyArray_SIZE(vector_npy)};
double*const vector_begin{reinterpret_cast<double*>(PyArray_DATA(vector_npy))};
double*const vector_end{vector_begin + vector_length};
for(double* vector_iterator{vector_begin}; vector_iterator != vector_end; ++vector_iterator)
{
if(vector_iterator != vector_begin)
{
std::cout << ", ";
}
std::cout << *vector_iterator;
}
std::cout << std::endl;
return Py::None();
}
Обратите внимание на истинный аргумент в качестве второго параметра для конструкторов Py::Object для "собственных" объектов! Пример расширения cpython3, которое использует API Numpy C в сочетании с PyCXX с cmake для сборки. Ссылка на конкретный коммит, потому что я рассматриваю переключение этого расширения обратно на использование Cython.