В настоящее время при работе с python + pybind11 мне неприятно работать с типизированными классами/структурами С++.
Я хотел бы изменить свои привязки, чтобы они генерировали простой класс Python с __init__
и простой функцией, как показано ниже. Что-то похожее на осуществимое?
Обоснование:
В настоящее время у меня есть структура, которую я генерирую с помощью C++, но в ней есть много тяжелых std::vector<float>
, которые я хотел бы передать в python и сохранить в виде массивов numpy внутри аналогичного класса интерфейса python. (бонусные баллы, если вы можете сказать мне, как быстро перемещать векторы в массивы numpy!)
Я уже полностью связал свою структуру С++ с pybind11, поэтому мне кажется, что я знаю, что делаю... однако я не могу понять, возможно ли это!
Итак, в качестве учебного упражнения, могу ли я создать следующий класс Python через pybind11?
>>> python
class MyStruct:
def __init__(self, A_in, descriptor_in):
self.A = A_in
self.descriptor = descriptor_in
def add_to_vec(f_in):
self.A.append(f_in)
<<< python
Редактировать: я хочу сказать, что я «думаю», что это выполнимо с API-интерфейсом Python C, но я бы хотел избежать использования этого напрямую, если смогу. (но если вы думаете, что это единственный способ, пожалуйста, дайте мне знать:))
Edit2: (ответ @Erwan)
Единственный известный мне способ получить переменные класса по отдельности - это (показано ниже). Вы не можете использовать рекламируемый pybind интерфейс buffer_protocol
, если у вас есть более одного массива numpy в структуре, которую вы хотите получить. Однако для этого требуется создать только функцию .def
интерфейса python (не идеальную), которая указывает (что, как я думаю, является копией) исходных данных (так что это вероятно медленно, я не проверял это, но я не уверен, был ли это взлом или правильный способ получить векторы в массивы numpy).
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <vector>
#include <string>
struct Pet {
Pet(const std::string &name) : name(name) {
bdata.push_back(22.);
bdata.push_back(23.1);
bdata.push_back(24.);
bdata.push_back(2222.);
}
void setName(const std::string &name_) { name = name_; }
const std::string &getName() const { return name; }
std::string name;
std::vector<float> bdata;
};
namespace py = pybind11;
PYBIND11_MODULE(example, m) {
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &>())
.def("setName", &Pet::setName)
.def("getName", &Pet::getName)
.def("bdata", [](Pet &m) -> py::array {
py::buffer_info buff_info(py::buffer_info(
m.bdata.data(), /* Pointer to buffer */
sizeof(float), /* Size of one scalar */
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */
m.bdata.size() /* Number of dimensions */
));
return py::array(buff_info);
});
}
std::vector
-›list
, и после этого вы можете преобразовать список в массив numpy. если вы предпочитаете вектор прямого преобразования вместо numpy, вам придется использовать интерфейс буфера, описанный здесь pybind11.readthedocs.io/en/master/advanced/pycpp/numpy.html - person Erwan   schedule 10.09.2019