У меня есть класс в c ++, содержащий среди прочего std::function
. Через pybind11 я создал привязку для этого класса, которая работала нормально. Теперь я хотел бы сделать класс маринованным. Однако, при попытке выбрать экземпляр класса в python, я получаю TypeError: can't pickle PyCapsule objects
.
Чтобы быть точным, вот минимальный пример: класс c ++ выглядит как
#include<functional>
using Function = std::function<double(double)>;
struct Test {
Function func;
};
Код для генерации python привязки читает
#include "pybind11/pybind11.h"
#include "pybind11/functional.h"
namespace py = pybind11;
PYBIND11_MODULE(my_module, m) {
py::class_<Test>(m, "Test")
.def(py::init<Function>())
.def(py::pickle(
[](const Test& t)
{
return py::make_tuple(t.func);
},
[](py::tuple tup)
{
return Test{tup[0].cast<Function>()};
}
));
}
Теперь (после того, как выше было построено), если кто-то пытается выбрать экземпляр класса в python
import pickle
from my_module import Test
def identity(entity):
return entity
if __name__ == "__main__":
test = Test(identity)
with open('test.pickle', 'wb') as out_file:
pickle.dump(test, out_file)
каждый получает ошибку, упомянутую выше:
TypeError: can't pickle PyCapsule objects
, которая поднимается линией pickle.dump(test, out_file)
.
Есть ли способ заставить травление работать без потери общности? То есть мне бы очень хотелось иметь возможность вызывать класс с произвольным python вызовом с подписью float -> float
.
Получается такая же ошибка, если func
заключен в py::cpp_function
, то есть, если заменить return py::make_tuple(t.func)
на return py::make_tuple(py::cpp_function{t.func})
.