在Python和C/C++之间共享std::vector<std::vector>数据
在Python和C/C++之间共享嵌套向量数据(std::vector<std::vector<int>>
)可以通过几种方法实现。以下是几种常见的方法:
方法1: 使用Cython
Cython是连接Python和C++的很好选择,它可以直接处理C++ STL容器。
- 创建
.pyx
文件(例如vector_sharing.pyx
):
# distutils: language = c++
# distutils: extra_compile_args = -std=c++11from libcpp.vector cimport vectorcdef extern from *:"""std::vector<std::vector<int>> process_vectors(const std::vector<std::vector<int>>& input) {std::vector<std::vector<int>> result;for (const auto& inner : input) {std::vector<int> temp;for (int val : inner) {temp.push_back(val * 2); // 示例处理}result.push_back(temp);}return result;}"""vector[vector[int]] process_vectors(const vector[vector[int]]& input)def process_vectors_py(list input_list):cdef vector[vector[int]] cpp_inputcdef vector[int] temp# 将Python列表转换为C++ vector<vector<int>>for inner_list in input_list:temp = inner_listcpp_input.push_back(temp)# 调用C++函数cdef vector[vector[int]] result = process_vectors(cpp_input)# 将结果转换回Python列表py_result = []for inner in result:py_result.append(inner)return py_result
方法2: 使用pybind11
pybind11是一个轻量级的C++库,用于将C++代码暴露给Python。
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>namespace py = pybind11;std::vector<std::vector<int>> process_vectors(const std::vector<std::vector<int>>& input) {std::vector<std::vector<int>> result;for (const auto& inner : input) {std::vector<int> temp;for (int val : inner) {temp.push_back(val * 2); // 示例处理}result.push_back(temp);}return result;
}PYBIND11_MODULE(vector_example, m) {m.def("process_vectors", &process_vectors, "Process nested vectors");
}
编译后,在Python中可以这样使用:
import vector_exampleinput_data = [[1, 2, 3], [4, 5, 6]]
result = vector_example.process_vectors(input_data)
print(result) # 输出: [[2, 4, 6], [8, 10, 12]]
方法3: 使用ctypes和C接口
如果你不想使用C++ STL,可以创建一个C接口:
- C++代码(
vector_interface.cpp
):
#include <vector>extern "C" {// 创建二维向量void* create_vector2d() {return new std::vector<std::vector<int>>();}// 添加一维向量void add_vector1d(void* vec2d, int* data, int size) {auto& v = *reinterpret_cast<std::vector<std::vector<int>>*>(vec2d);v.emplace_back(data, data + size);}// 处理数据void process_vectors(void* vec2d) {auto& v = *reinterpret_cast<std::vector<std::vector<int>>*>(vec2d);for (auto& inner : v) {for (auto& val : inner) {val *= 2; // 示例处理}}}// 获取数据int* get_inner_array(void* vec2d, int outer_idx, int* size) {auto& v = *reinterpret_cast<std::vector<std::vector<int>>*>(vec2d);*size = v[outer_idx].size();return v[outer_idx].data();}// 释放内存void free_vector2d(void* vec2d) {delete reinterpret_cast<std::vector<std::vector<int>>*>(vec2d);}
}
- Python代码:
import ctypes
import numpy as np# 加载共享库
lib = ctypes.CDLL('./vector_interface.so') # 或 .dll 在Windows上# 定义函数原型
lib.create_vector2d.restype = ctypes.c_void_p
lib.add_vector1d.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.c_int]
lib.process_vectors.argtypes = [ctypes.c_void_p]
lib.get_inner_array.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_int)]
lib.get_inner_array.restype = ctypes.POINTER(ctypes.c_int)
lib.free_vector2d.argtypes = [ctypes.c_void_p]def process_data(py_data):# 创建二维向量vec2d = lib.create_vector2d()# 添加数据for inner_list in py_data:arr = (ctypes.c_int * len(inner_list))(*inner_list)lib.add_vector1d(vec2d, arr, len(inner_list))# 处理数据lib.process_vectors(vec2d)# 获取结果result = []for i in range(len(py_data)):size = ctypes.c_int()ptr = lib.get_inner_array(vec2d, i, ctypes.byref(size))result.append([ptr[j] for j in range(size.value)])# 释放内存lib.free_vector2d(vec2d)return result# 使用示例
input_data = [[1, 2, 3], [4, 5, 6]]
output = process_data(input_data)
print(output) # 输出: [[2, 4, 6], [8, 10, 12]]
方法4: 使用NumPy和C++
如果性能是关键,可以使用NumPy数组并通过C接口传递:
- C++代码:
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <vector>namespace py = pybind11;py::array_t<int> process_nested_arrays(py::array_t<int> input) {py::buffer_info buf = input.request();if (buf.ndim != 2)throw std::runtime_error("Number of dimensions must be 2");int* ptr = static_cast<int*>(buf.ptr);size_t rows = buf.shape[0];size_t cols = buf.shape[1];// 处理数据 (这里简单地将每个元素乘以2)for (size_t i = 0; i < rows; i++) {for (size_t j = 0; j < cols; j++) {ptr[i * cols + j] *= 2;}}return input;
}PYBIND11_MODULE(numpy_example, m) {m.def("process_nested_arrays", &process_nested_arrays, "Process nested arrays");
}
- Python代码:
import numpy as np
import numpy_example# 创建2D NumPy数组
input_data = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)# 处理数据
output = numpy_example.process_nested_arrays(input_data)
print(output)
性能考虑
- 数据拷贝:大多数方法需要在Python和C++之间拷贝数据,这可能成为性能瓶颈。
- 内存共享:对于大型数据集,考虑使用内存映射或共享内存来避免拷贝。
- 不规则嵌套:如果内部向量长度不一致,NumPy方法可能不太适用,此时pybind11或Cython更合适。
选择哪种方法取决于你的具体需求、性能要求和开发环境偏好。pybind11通常是最简单和灵活的选择,而NumPy方法在数据规则且需要高性能时最有效。