使用 pybind11 从 python 传递指向 C++ 的指针
passing pointer to C++ from python using pybind11
我使用 pybind11 创建了以下 class:
py::class_<Raster>(m, "Raster")
.def(py::init<double*, std::size_t, std::size_t, std::size_t, double, double, double>());
但是我不知道如何在 Python 中调用这个构造函数。我看到 Python 需要一个 float 来代替 double*,但我似乎无法调用它.
我已经试过了,ctypes.data_as(ctypes.POINTER(ctypes.c_double))
但是这不起作用...
编辑:
我从@Sergei 的回答中提取了答案。
py::class_<Raster>(m, "Raster", py::buffer_protocol())
.def("__init__", [](Raster& raster, py::array_t<double> buffer, double spacingX, double spacingY, double spacingZ) {
py::buffer_info info = buffer.request();
new (&raster) Raster3D(static_cast<double*>(info.ptr), info.shape[0], info.shape[1], info.shape[2], spacingX, spacingY, spacingZ);
})
Pybind 进行自动转换。当您绑定 f(double *)
时,参数被假定为指向单个值的指针,而不是指向数组开始的指针,因为从 python 端期望这样的输入是非常不自然的。所以 pybind 将使用此逻辑转换参数。
如果您需要将原始数组传递给 C++,请使用 py::buffer
,例如 here:
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
.def("__init__", [](Matrix &m, py::buffer b) {
typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
/* Request a buffer descriptor from Python */
py::buffer_info info = b.request();
/* Some sanity checks ... */
if (info.format != py::format_descriptor<Scalar>::format())
throw std::runtime_error("Incompatible format: expected a double array!");
if (info.ndim != 2)
throw std::runtime_error("Incompatible buffer dimension!");
auto strides = Strides(
info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar),
info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar));
auto map = Eigen::Map<Matrix, 0, Strides>(
static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
new (&m) Matrix(map);
});
要使其工作,您需要传递一个遵循 python 缓冲协议的类型。
我使用 pybind11 创建了以下 class:
py::class_<Raster>(m, "Raster")
.def(py::init<double*, std::size_t, std::size_t, std::size_t, double, double, double>());
但是我不知道如何在 Python 中调用这个构造函数。我看到 Python 需要一个 float 来代替 double*,但我似乎无法调用它.
我已经试过了,ctypes.data_as(ctypes.POINTER(ctypes.c_double))
但是这不起作用...
编辑:
我从@Sergei 的回答中提取了答案。
py::class_<Raster>(m, "Raster", py::buffer_protocol())
.def("__init__", [](Raster& raster, py::array_t<double> buffer, double spacingX, double spacingY, double spacingZ) {
py::buffer_info info = buffer.request();
new (&raster) Raster3D(static_cast<double*>(info.ptr), info.shape[0], info.shape[1], info.shape[2], spacingX, spacingY, spacingZ);
})
Pybind 进行自动转换。当您绑定 f(double *)
时,参数被假定为指向单个值的指针,而不是指向数组开始的指针,因为从 python 端期望这样的输入是非常不自然的。所以 pybind 将使用此逻辑转换参数。
如果您需要将原始数组传递给 C++,请使用 py::buffer
,例如 here:
py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
.def("__init__", [](Matrix &m, py::buffer b) {
typedef Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic> Strides;
/* Request a buffer descriptor from Python */
py::buffer_info info = b.request();
/* Some sanity checks ... */
if (info.format != py::format_descriptor<Scalar>::format())
throw std::runtime_error("Incompatible format: expected a double array!");
if (info.ndim != 2)
throw std::runtime_error("Incompatible buffer dimension!");
auto strides = Strides(
info.strides[rowMajor ? 0 : 1] / (py::ssize_t)sizeof(Scalar),
info.strides[rowMajor ? 1 : 0] / (py::ssize_t)sizeof(Scalar));
auto map = Eigen::Map<Matrix, 0, Strides>(
static_cast<Scalar *>(info.ptr), info.shape[0], info.shape[1], strides);
new (&m) Matrix(map);
});
要使其工作,您需要传递一个遵循 python 缓冲协议的类型。