带有类成员的pybind11缓冲协议

时间:2019-09-03 18:54:32

标签: python c++ pybind11

我正在尝试使用pybind11绑定一个看起来像这样的结构

struct myStruct {
 int na;
 int nb;
 double* a;
 double* b;
}

我不确定执行此操作的正确方法。 pybind11 documentation中的示例显示了如何将缓冲区协议语义附加到对象,而不附加到类成员。

我无法将myStruct的接口更改为包含std::vector,这使我可以使用通常的.def_readwrite()

我试图做这样的事情

py::class_<myStruct>(m, "myStruct")
    .def_property("a",
        [](myStruct &s) {return py::array<double>({s.na}, {sizeof(double), s.a};)},
        [](myStruct &s, py::array_t<double> val) {std::copy((double*) val.request().ptr, (double*) val.request().ptr + s.na, s.a);)}
    )

哪个可以编译,但是在python中我看不到基础数据中的更改会持续存在

print(my_struct.a[0]) # prints 0.0
my_struct.a[0] = 123.0
print(my_struct.a[0]) # still prints 0.0

1 个答案:

答案 0 :(得分:0)

最有可能不是最优雅的答案,但是也许它为您提供了一个起点和临时解决方案。我认为您需要做的是使用共享指针。

https://github.com/pybind/pybind11/issues/1150下,有人提出了类似的要求,但我无法使其适应您的示例,而对您的结果却没有改变,只是得到了相同的结果。

在您的特定示例中,对我有用的是使用shared_ptr并为指针定义了setter和getter函数,并为pybin11类定义了简单的def_property。

class class_DATA{
    public: 
        int na;
        std::shared_ptr<double> a;  

        void set_a(double a){*class_DATA::a = a; };
        double get_a(void){return *class_DATA::a; };
};

PYBIND11_MODULE(TEST,m){
  m.doc() = "pybind11 example plugin";
 //the costum class
 py::class_<class_DATA>(m, "class_DATA", py::dynamic_attr())
  .def(py::init<>())    //needed to define constructor
  .def_readwrite("na", &class_DATA::na)
  .def_property("a", &class_DATA::get_a, &class_DATA::set_a, py::return_value_policy::copy);
}