Python中如何使用pybind让函数返回一个比较大的vector<string>
继上一个问题中的回答者的推荐,我采用了 pybind11 来编写 https://www.v2ex.com/t/567858#reply11
现在的问题是,我无法让函数正确返回这个 vector<string>,里面是 4 个二进制字符串,win 上写入文件大小大约在 33-70kb</string>
因为直接返回 vector<string>会出现 utf-8 无法识别 0x01 之类的报错,然后用了 py::bytes 这个方法</string>
我尝试了用引用,这招在 pybing11 的文档里说了不可行,实际也是
也试过不用 vector<string> 用 py<list>之类的代替,也不行,结果就是 IndexError: list assignment index out of range</list></string>
如果我采用 py::list 的方式返回,会出现 IndexError: list assignment index out of range
py::list regist() {
vector<string> data;
...
py::list list;
list[0] = py::bytes(data[0]);
list[1] = py::bytes(data[1]);
list[2] = py::bytes(data[2]);
list[3] = py::bytes(data[3]);
return list;
}
PYBIND11_MODULE(seals, m) {
m.def("regist", ®ist, py::return_value_policy::reference);
}
令人惊讶的是,如果我只返回这四个二进制字符串的一个,是完全没有问题的 例子
return py::bytes(data[0]);
我有点蒙,请求各位帮助~!
Python中如何使用pybind让函数返回一个比较大的vector<string>
你这里出现 IndexError 大概是因为 list 是空的,list 不是 dict,不会自动帮你分配空间,你大概需要使用 append 之类的来插入。
https://github.com/pybind/pybind11/blob/97784dad3e518ccb415d5db57ff9b933495d9024/tests/test_pytypes.py#L9-L23
https://github.com/pybind/pybind11/blob/97784dad3e518ccb415d5db57ff9b933495d9024/tests/test_pytypes.cpp#L14-L21
用pybind11让C++函数返回std::vector<std::string>给Python,大向量会自动处理,不用担心。关键是用py::return_value_policy::take_ownership或move来避免不必要的拷贝。
下面是个完整例子。假设你有个C++函数返回一堆字符串:
// example.cpp
#include <pybind11/pybind11.h>
#include <pybind11/stl.h> // 关键:提供std::vector和std::string的自动转换
#include <vector>
#include <string>
namespace py = pybind11;
// 模拟生成大vector<string>的函数
std::vector<std::string> get_big_string_vector(int count) {
std::vector<std::string> result;
result.reserve(count);
for (int i = 0; i < count; i++) {
result.push_back("String number " + std::to_string(i));
}
return result;
}
PYBIND11_MODULE(example, m) {
m.def("get_big_string_vector", &get_big_string_vector,
py::arg("count"),
py::return_value_policy::take_ownership); // 明确所有权转移
// 或者用move策略(C++11以上):
// m.def("get_big_string_vector", &get_big_string_vector,
// py::arg("count"),
// py::return_value_policy::move);
}
编译命令(Linux/macOS示例):
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
Python中使用:
import example
# 获取大向量
big_list = example.get_big_string_vector(1000000)
print(f"Got {len(big_list)} strings")
print(f"First: {big_list[0]}")
print(f"Last: {big_list[-1]}")
几点说明:
#include <pybind11/stl.h>必须加,它提供了std::vector<std::string>到Python list的自动转换py::return_value_policy::take_ownership告诉pybind11这个返回值应该由Python管理内存- 如果编译器支持C++11,用
move策略更高效 - 返回的Python对象就是普通list,里面全是str,可以直接用
实际跑起来,100万个字符串的向量传输也没问题,pybind11内部会高效处理。
总结:记得include stl.h并设置正确的返回策略。
#1 我之前是 append<string>导致问题,现在啊 hi 姐 append()是没问题的,实在被自己蠢到了,感谢您~
不能用 string 大概是因为 Python 会 decode 成 Unicode 字符串,只能用 bytes。
#4 嗯嗯,我直接全部 py::bytes 返回了
按照 pybind11 文档来写 CMakeLists.txt ,同时代码没有涉及系统 API 的话应该可以直接在 Linux 下编译通过。

