使用pybind11传递std::vector、std::map等STL容器的问题求解
问题解决步骤
1 修复类未实例化的基础错误
你当前所有报错的核心诱因是没有正确实例化绑定类,仅把类对象本身赋值给了变量:
- 实例化
ProbTree需要写成pt = sps_c.ProbTree()而非pt = sps_c.ProbTree - 实例化
VectorD/MapDD需要写成vd = sps_c.VectorD()、m = sps_c.MapDD()而非直接赋值类对象
你调用push_back报错就是因为在类而非实例上调用成员方法,修复实例化问题后即可正常使用push_back、索引访问等STL原生方法。
2 容器传参的两种可选方案
你使用了PYBIND11_MAKE_OPAQUE+bind_vector/bind_map的不透明容器绑定方案,该方案默认不会自动转换Python原生列表/字典到绑定容器类型,根据你的使用场景可以二选一解决:
方案A:轻量传值场景(无修改同步需求)
如果不需要在Python和C++两侧共享同一个容器实例,仅需要传值调用,可以删除以下代码:
PYBIND11_MAKE_OPAQUE(std::vector<double>); PYBIND11_MAKE_OPAQUE(std::map<double, double>); // 以及下方的bind_vector、bind_map绑定代码
只要保留#include <pybind11/stl.h>,pybind11会自动完成Python列表和std::vector、Python字典和std::map的类型转换,不需要额外绑定代码,直接传Python原生列表/字典即可调用方法,缺点是每次传参都会做全量拷贝,大数据量下效率较低。
方案B:共享实例场景(需要修改同步)
如果需要C++修改容器后Python侧同步看到结果(也就是你当前的需求),保留现有绑定代码即可,不需要新增样板代码,传参前先把Python原生列表转换为绑定容器实例即可:
# 用Python列表直接初始化绑定容器 vd = sps_c.VectorD([1.0, 2.0, 3.0]) m = sps_c.MapDD() # 调用方法 pt.process(vd) pt.predict(vd, m) # C++填充的map内容可以直接在Python侧读取,用法和原生字典一致 print(dict(m))
该方案没有数据拷贝,Python和C++操作的是同一个容器实例,修改会双向同步,完全满足你的需求。
完整正确调用示例
import sps_c # 实例化所有类 pt = sps_c.ProbTree() # 操作VectorD vd = sps_c.VectorD() vd.push_back(1.0) vd.push_back(2.0) # 调用process pt.process(vd) # 调用predict获取填充后的map prob_map = sps_c.MapDD() pt.predict(vd, prob_map) # 打印结果 for k, v in prob_map.items(): print(f"键: {k}, 概率: {v}")
不需要编写大量样板代码,pybind11已经封装了STL容器的全量绑定逻辑,你仅需要修复实例化错误,根据场景选择合适的绑定方案即可。
内容的提问来源于stack exchange,提问作者John Glen
相关产品推荐
相关产品推荐

