how to return numpy.array from boost::python? how to return numpy.array from boost::python? numpy numpy

how to return numpy.array from boost::python?


UPDATE: the library described in my original answer (https://github.com/ndarray/Boost.NumPy) has been integrated directly into Boost.Python as of Boost 1.63, and hence the standalone version is now deprecated. The text below now corresponds to the new, integrated version (only the namespace has changed).

Boost.Python now includes a moderately complete wrapper of the NumPy C-API into a Boost.Python interface. It's pretty low-level, and mostly focused on how to address the more difficult problem of how to pass C++ data to and from NumPy without copying, but here's how you'd do a copied std::vector return with that:

#include "boost/python/numpy.hpp"namespace bp = boost::python;namespace bn = boost::python::numpy;std::vector<double> myfunc(...);bn::ndarray mywrapper(...) {    std::vector<double> v = myfunc(...);    Py_intptr_t shape[1] = { v.size() };    bn::ndarray result = bn::zeros(1, shape, bn::dtype::get_builtin<double>());    std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data()));    return result;}BOOST_PYTHON_MODULE(example) {    bn::initialize();    bp::def("myfunc", mywrapper);}


A solution that doesn't require you to download any special 3rd party C++ library (but you need numpy).

#include <numpy/ndarrayobject.h> // ensure you include this headerboost::python::object stdVecToNumpyArray( std::vector<double> const& vec ){      npy_intp size = vec.size();     /* const_cast is rather horrible but we need a writable pointer        in C++11, vec.data() will do the trick        but you will still need to const_cast      */      double * data = size ? const_cast<double *>(&vec[0])         : static_cast<double *>(NULL);     // create a PyObject * from pointer and data       PyObject * pyObj = PyArray_SimpleNewFromData( 1, &size, NPY_DOUBLE, data );      boost::python::handle<> handle( pyObj );      boost::python::numeric::array arr( handle );    /* The problem of returning arr is twofold: firstly the user can modify      the data which will betray the const-correctness       Secondly the lifetime of the data is managed by the C++ API and not the       lifetime of the numpy array whatsoever. But we have a simple solution..     */       return arr.copy(); // copy the object. numpy owns the copy now.  }

Of course you might write a function from double * and size, which is generic then invoke that from the vector by extracting this info. You could also write a template but you'd need some kind of mapping from data type to the NPY_TYPES enum.


It's a bit late, but after many unsuccessful tries I found a way to expose c++ arrays as numpy arrays directly. Here is a short C++11 example using boost::python and Eigen:

#include <numpy/ndarrayobject.h>#include <boost/python.hpp>#include <Eigen/Core>// c++ typestruct my_type {  Eigen::Vector3d position;};// wrap c++ array as numpy arraystatic boost::python::object wrap(double* data, npy_intp size) {  using namespace boost::python;  npy_intp shape[1] = { size }; // array size  PyObject* obj = PyArray_New(&PyArray_Type, 1, shape, NPY_DOUBLE, // data type                              NULL, data, // data pointer                              0, NPY_ARRAY_CARRAY, // NPY_ARRAY_CARRAY_RO for readonly                              NULL);  handle<> array( obj );  return object(array);}// module definitionBOOST_PYTHON_MODULE(test){  // numpy requires this  import_array();  using namespace boost::python;  // wrapper for my_type  class_< my_type >("my_type")    .add_property("position", +[](my_type& self) -> object {        return wrap(self.position.data(), self.position.size());      });}

The example describes a "getter" for the property. For the "setter", the easiest way is to assign the array elements manually from a boost::python::object using a boost::python::stl_input_iterator<double>.