[BUG]: How to create a class that has access to one or more Numpy arrays?
goofy2k opened this issue · comments
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.11.1 (latest)
Problem description
I want to create a C++ class that can use a Numpy array. So I started to read the docs on using object-oriented code and Numpy arrays. I tested the examples in these sections and they behave well.
My own code for a class MC_box_1 is based on the struct Pet example (pybind11 documentation > Object-oriented code) and the modify_array example (pybind11 documentation > Python C++ interface >> Numpy). Both examples behave OK but when I combine them in a class MC_box_1 I get an error that is similar to the one described as in issue #2274 and have no clue how to solve this. I hope that someone can be of help on this.
My next step would be to insert the array already in the constructor.
My code:
Reproducible example code
// C++
// add a Numpy attribute (temp use setter)
class MC_box_1 {
public:
MC_box_1(const std::string& name) : name(name) { }
void setName(const std::string& name_) { name = name_; }
const std::string& getName() const { return name; }
// preferably set input_array in constructor, first test with setArray
void setArray(py::array_t<double> input_array_) {
input_array = input_array_;
py::buffer_info buf_info = input_array.request();
double* ptr = static_cast<double*>(buf_info.ptr);
}
std::string name;
py::array_t<double> input_array;
};
// binding code
// add a Numpy array, later use it via the constructor
py::class_<MC_box_1>(m, "MC_box_1")
.def(py::init<const std::string&>())
.def("setName", &MC_box_1::setName)
.def("getName", &MC_box_1::getName)
.def("setArray", &MC_box_1::setArray)
//__repr__ method to print the object
.def("__repr__", // Binding lambda functions
[](const MC_box_1& a) { // uses a "stateless" lambda closure [] (vs stateful)
return "<MCrun_pybind_0.MC_box_1 named '" + a.name + " '>";
});
//Python
# Object oriented code
p = MCrun_pybind_0.Pet("Molly")
print(p)
print(p.getName())
p.setName("Charly")
print(p.getName()) # behaves OK
mybox_0 = MCrun_pybind_0.MC_box_0("simple box") # based on pybind11 docs, struct Pet example
print("print(mybox_0)",mybox_0)
# first test Numpy array as such
arr = np.array([1.0, 2.0, 3.0, 4.0])
print("type(arr) ",type(arr))
MCrun_pybind_0.modify_array(arr) # taken from pybind11 docs
print(arr) # Expected output: [2.0, 4.0, 6.0, 8.0] OK
arr_1 = np.array([1.0, 2.0, 3.0, 4.0])
print("type(arr_1) ",type(arr_1))
mybox_1 = MCrun_pybind_0.MC_box_1("box including Numpy array") # based on struct Pet (now class) and modify_array examples
print("print(mybox_1)",mybox_1) # behaves OK
MCrun_pybind_0.MC_box_1.setArray(arr_1) # ERROR !
Although I use the same array and calling code as in the modify_array example I get an error on using the setArray method:
TypeError: setArray(): incompatible function arguments. The following argument types are supported:
1. (self: MCrun_pybind_0.MC_box1, arg0: numpy.ndarray[numpy.float64]) -> None
Invoked with: array([1., 2., 3., 4.])
### Is this a regression? Put the last known working version here if it is.
Not a regression
Excuse me: the modify_array example was NOT taken from the pybind 11 documentation. I took it from "Pybind11: Numpy Compatible Arrays" on scicoding.org
In attempts to let the array type match the supported argument type, I tried to change the array dtype at creation time of the array. Without succes.
# arr_1 = np.array([1.0, 2.0, 3.0, 4.0], dtype='d')
# arr_1 = np.array([1.0, 2.0, 3.0, 4.0], np.longdouble) #strange: now the "invoked with" type is exactly what is reported to be the supported type, but still throws an error
# arr_1 = np.array([1.0, 2.0, 3.0, 4.0], np.float64)
# as alternatives for
arr_1 = np.array([1.0, 2.0, 3.0, 4.0])