Pybind11如何将N维numpy数组从Python传递到C++并适配std::vector
二维numpy数组传递到C++的正确实现
你之前的写法报错的核心原因是:numpy的多维数组是连续存储的单块内存,并非嵌套的数组结构,因此不能用py::array_t<py::array_t<float>>这种嵌套类型声明。
1. C++侧参数声明
直接使用带存储格式约束的py::array_t即可,示例如下:
#include <pybind11/pybind11.h> #include <pybind11/numpy.h> #include <vector> #include <stdexcept> namespace py = pybind11; // 如果你用的是Python默认的float(对应numpy float64),把<float>替换成<double>即可 void modify_array(py::array_t<float, py::array::c_style | py::array::forcecast> input_arr) { // 逻辑实现见下文 }
参数中的py::array::c_style要求数组为行优先存储,py::array::forcecast会自动转换兼容的数值类型,避免格式报错。
2. 实现类似std::vector的读写效果
提供两种常用实现方式,可按需选择:
方式一:零拷贝直接操作(修改直接同步到Python侧原数组)
不需要额外内存拷贝,性能最高:
void modify_array(py::array_t<float, py::array::c_style | py::array::forcecast> input_arr) { py::buffer_info buf = input_arr.request(); // 校验维度 if (buf.ndim != 2) { throw std::runtime_error("输入必须为二维数组"); } size_t rows = buf.shape[0]; size_t cols = buf.shape[1]; float* data_ptr = static_cast<float*>(buf.ptr); // 封装和vector[i][j]一致的访问接口 auto arr = [&](size_t row, size_t col) -> float& { if (row >= rows || col >= cols) throw std::out_of_range("数组下标越界"); return data_ptr[row * cols + col]; }; // 读写操作和vector完全一致 float val = arr(0, 1); // 读取第0行第1列元素 arr(1, 2) = 123.45f; // 修改第1行第2列元素,修改直接生效到Python侧数组 }
方式二:转成std::vector<std::vector>操作(兼容全部vector接口)
适合需要用到vector专属方法的场景,修改后可手动同步回原数组:
void modify_array(py::array_t<float, py::array::c_style | py::array::forcecast> input_arr) { py::buffer_info buf = input_arr.request(); if (buf.ndim != 2) { throw std::runtime_error("输入必须为二维数组"); } size_t rows = buf.shape[0]; size_t cols = buf.shape[1]; float* data_ptr = static_cast<float*>(buf.ptr); // 转成嵌套vector std::vector<std::vector<float>> vec_arr(rows, std::vector<float>(cols)); for (size_t i = 0; i < rows; i++) { for (size_t j = 0; j < cols; j++) { vec_arr[i][j] = data_ptr[i * cols + j]; } } // 此处可使用任意vector的方法操作vec_arr,比如push_back、sort等 vec_arr[0].push_back(4.0f); std::sort(vec_arr[1].begin(), vec_arr[1].end()); // 如需将修改同步回原numpy数组,遍历写回即可(注意如果修改了vector长度,要做对应维度校验) for (size_t i = 0; i < rows; i++) { for (size_t j = 0; j < cols; j++) { data_ptr[i * cols + j] = vec_arr[i][j]; } } }
3. 绑定与Python侧调用
函数绑定和普通pybind11函数一致:
PYBIND11_MODULE(numpy_utils, m) { m.def("modify_array", &modify_array, "修改二维float numpy数组"); }
Python侧直接传入numpy数组即可:
import numpy as np import numpy_utils arr = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float32) numpy_utils.modify_array(arr) print(arr) # 可看到C++侧的修改已经同步到Python数组
内容的提问来源于stack exchange,提问作者Munkybutt
相关产品推荐
相关产品推荐

