I'm trying to pass a C struct from C++ into python as a numpy array using boost::python. I know there are simplier ways to pass C structs to python, but the reason I want to use numpy arrays is that solution is part of a reflection model, so the data type needs to be generated dynamically from a string.
I can serialize the struct passing it to python as a string and call numpy.fromstring() in python which successfully converts it into a numpy array. However, this is not very efficient because converting it to a string copies the data instead of passing it to python by reference.
For example:
#include <boost/python.hpp>
using namespace boost::python;
struct MyRecord
{
uint32_t myInt;
char myString[4];
double myDouble;
};
class MyBaseClass
: public wrapper<MyBaseClass>
{
public:
void myCallback(const MyRecord& data)
{
object func = get_override("myCallback");
if (func) {
std::string dataStr(reinterpret_cast<const char*>(data), sizeof(data));
func(dataStr, "[('myInt','<u4'),('myString','|S4'),('myDouble','<f8')]");
}
}
};
BOOST_PYTHON_MODULE(example1)
{
class_<MyBaseClass>("MyBaseClass")
.def("myCallback", &MyBaseClass::myCallback);
}
#!/usr/bin/env python
import numpy
from example1 import MyBaseClass
class MyClass(MyBaseClass):
def myCallback(self, dataStr, dtypeStr):
dt = numpy.dtype(eval(dtypeStr))
data = numpy.fromstring(dataStr, dt)
print data # This is now a numpy array
What I'd really like to be able to do is to convert the struct to a numpy array in C++ and pass it by reference directly to python.
I've experimented with the boost::python::numeric::array class, but I'm having problems getting it to convert the C++ type into an numpy array. The constructor is throwing: "TypeError: No to_python (by-value) converter found for C++ type: MyRecord"
There some example code:
#include <boost/python.hpp>
#include <boost/python/exec.hpp>
#include <boost/python/numeric.hpp>
using namespace boost::python;
struct MyRecord
{
uint32_t myInt;
char myString[4];
double myDouble;
};
class MyBaseClass
: public wrapper<MyBaseClass>
{
public:
void myCallback(const MyRecord& data)
{
object func = get_override("myCallback");
if (func) {
object dtype = exec("eval(\"[('myInt','<u4'),('myString','|S4'),('myDouble','<f8')]\")");
func(numeric::array(data, dtype)); // numeric::array throws
}
}
};
BOOST_PYTHON_MODULE(example2)
{
class_<MyBaseClass>("MyBaseClass")
.def("myCallback", &MyBaseClass::myCallback);
}
#!/usr/bin/env python
import numpy
from example2 import MyBaseClass
class MyClass(MyBaseClass):
def myCallback(self, data):
print data # This is a numpy array passed from C++
Thanks,
Paul