Reputation: 303
I'm using pybind11
to create a Python binding for my C++ library that uses Eigen types. However, when I try to bind a struct that contains an Eigen::Matrix
, the corresponding generated Python class has all the ndarray
(the Python destination class for Eigen::Matrix
members) elements with the Writeable flag set to false, which are therefore non-modifiable. I've managed to reduce my problem to the following MWE:
// binding.cpp
#include "Eigen/Dense"
#include "pybind11/pybind11.h"
#include "pybind11/eigen.h"
struct Example {
Eigen::Matrix<double, 3, 1> m;
};
namespace py = pybind11;
PYBIND11_MODULE(MyBinding, m)
{
py::class_<Example>(m, "Example")
.def(py::init<>())
.def_readwrite("m", &Example::m);
}
# script.py
import MyBinding
ex = MyBinding.Example()
# ex.m has Writeable flag equal to false!
On the contrary, when binding the following code, everything works as expected, i.e. the value returned by f
, when called in Python, is modifiable (has the Writeable flag set to true):
Eigen::Matrix<double,3,1> f() {
return {};
}
PYBIND11_MODULE(MyBinding, m)
{
m.def("f", &f);
}
What am I missing here? Thank you for any help!
Upvotes: 3
Views: 592
Reputation: 1799
def_readwrite(⋯)
is a shortcut for def_property(⋯)
(source link) where the getter takes the class instance by const
-reference. Therefore the resulting numpy array is not modifiable.
All you need to do is to write custom getter and setter functions:
namespace py = pybind11;
PYBIND11_MODULE( MyBinding, m )
{
py::class_<Example>( m, "Example" )
.def(py::init<>())
.def_property( "m",
// Getter
[]( Example const& self )
{
return self.m;
},
// Setter
[]( Example& self, Eigen::Matrix<double,3,1> const& val )
{
self.m = val;
}
)
;
}
Caution: untested code, you may need to pass an extra return-value policy argument
Upvotes: 3