如何通过Pybind11从py::memoryview获取py::buffer_info及数组元信息?
在Pybind11中从memoryview获取缓冲区信息(无需数据复制)
当然可以实现,而且有两种可靠的无复制方案,直接获取memoryview底层的缓冲区元数据(指针、形状、步长等):
方案1:利用pybind11的py::buffer接口(推荐)
pybind11的memoryview对象支持通过request()方法获取对应的py::buffer实例,进而拿到py::buffer_info——这是pybind11封装的缓冲区信息结构体,包含了你需要的所有字段,且全程无数据复制。
代码示例
#include <pybind11/pybind11.h> namespace py = pybind11; void handle_memoryview(py::memoryview mv) { // 从memoryview请求buffer对象 py::buffer buf = mv.request(); // 获取buffer_info结构体 auto buf_info = buf.request(); // 提取所需信息 void* data_ptr = buf_info.ptr; int num_dims = buf_info.ndim; std::vector<ssize_t> shape = buf_info.shape; std::vector<ssize_t> strides = buf_info.strides; ssize_t elem_size = buf_info.itemsize; // 示例:输出信息 py::print("数据指针:", data_ptr); py::print("维度数:", num_dims); py::print("形状:", shape); py::print("步长:", strides); py::print("元素字节大小:", elem_size); } PYBIND11_MODULE(my_module, m) { m.def("handle_memoryview", &handle_memoryview, "接收memoryview并提取缓冲区信息"); }
方案2:直接调用Python C API
如果需要更底层的控制,可以直接通过pybind11拿到memoryview对应的PyObject*,调用Python原生的PyMemoryView_GET_BUFFER宏来获取Py_buffer结构体,同样无需复制数据。注意使用后必须调用PyBuffer_Release释放资源,避免内存泄漏。
代码示例
#include <pybind11/pybind11.h> #include <Python.h> namespace py = pybind11; void handle_memoryview_low_level(py::memoryview mv) { PyObject* mv_obj = mv.ptr(); Py_buffer buffer; // 获取底层缓冲区 if (PyMemoryView_GET_BUFFER(mv_obj, &buffer) != 0) { throw py::error_already_set(); } // 提取信息 void* data_ptr = buffer.buf; int num_dims = buffer.ndim; std::vector<ssize_t> shape(buffer.shape, buffer.shape + num_dims); std::vector<ssize_t> strides(buffer.strides, buffer.strides + num_dims); ssize_t elem_size = buffer.itemsize; // 示例输出 py::print("\n底层API获取的信息:"); py::print("数据指针:", data_ptr); py::print("维度数:", num_dims); py::print("形状:", shape); py::print("步长:", strides); py::print("元素字节大小:", elem_size); // 必须释放缓冲区 PyBuffer_Release(&buffer); } PYBIND11_MODULE(my_module, m) { m.def("handle_memoryview_low_level", &handle_memoryview_low_level, "用底层API处理memoryview"); }
关键注意事项
- 两种方案都不会复制数据,直接访问memoryview指向的底层内存区域。
- 方案1更符合pybind11的封装风格,无需手动管理资源,推荐优先使用。
- 如果memoryview是只读的,获取的指针也会是只读的,写入操作会触发错误,需根据Python端传入的memoryview权限处理。
内容的提问来源于stack exchange,提问作者tmlen
相关产品推荐
相关产品推荐

