pybind11是C++与Python交互最轻量主流方案,通过PYBIND11_MODULE声明模块、m.def()绑定函数、编译为.so/.pyd实现调用;支持STL类型自动转换,类绑定需pybind11::class_。

用 pybind11 是目前 C++ 与 Python 交互最轻量、最主流的选择——它不依赖 Python C API 的底层细节,编译快,接口写法接近 Python 原生风格,且头文件即用,无需链接庞大库。
怎么让 Python 调用 C++ 函数?
核心是用 pybind11 将 C++ 函数“绑定”为 Python 可导入的模块。关键步骤:声明模块、注册函数、编译成 .so(Linux/macOS)或 .pyd(Windows)。
- 必须包含
#include,并用PYBIND11_MODULE宏定义模块入口 - C++ 函数本身无需修改,直接在绑定代码里用
m.def()暴露出去 - 编译需启用 C++11 或更高标准(
-std=c++11),并链接pybind11的构建系统(推荐用cmake+find_package(pybind11))
/* example.cpp */ #includeint add(int a, int b) { return a + b; }
PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; m.def("add", &add, "A function that adds two integers"); }
如何传递和返回复杂类型(比如 std::vector)?
pybind11 自动支持常见 STL 类型的转换,但默认是值传递(拷贝),对大对象可能影响性能;若需零拷贝或原地修改,得显式控制。
-
std::vector、std::string、std::map等可直接作为参数或返回值,无需额外声明 - 返回
std::vector时,Python 侧拿到的是list;传入list也会自动转为std::vector - 若想避免拷贝(例如只读访问大数组),可用
pybind11::array_t或pybind11::buffer,配合 NumPy 使用
/* vector_example.cpp */ #include#include // 必须包含此头文件以支持 STL 容器自动转换 #include std::vector
get_range(int n) { std::vector v(n); for (int i = 0; i < n; ++i) v[i] = i; return v; } PYBIND11_MODULE(vector_example, m) { m.def("get_range", &get_range); }
编译时常见错误有哪些?
多数问题出在环境路径、Python 版本不匹配或 CMake 配置遗漏,不是代码逻辑问题。
立即学习“Python免费学习笔记(深入)”;
-
ImportError: dynamic module does not define module export function:模块名与PYBIND11_MODULE第一个参数不一致,或编译后文件名不是xxx.cpython-*.so形式(建议用set_target_properties(... PROPERTIES PREFIX "")清除前缀) -
undefined symbol: _Py_ZeroStruct:链接了错误的 Python 库(比如系统 Python 和 conda Python 混用),检查cmake -DPYTHON_EXECUTABLE是否指向你实际运行python的那个解释器 - Windows 下报
LNK2001: unresolved external symbol PyInit_xxx:没加__declspec(dllexport)?不用——pybind11已通过宏处理,只需确认项目属性中“配置类型”是Dynamic Library (.dll),且输出扩展名为.pyd
要不要用 pybind11::class_ 绑定 C++ 类?
要,而且非常值得。相比纯函数,类绑定能自然映射面向对象逻辑,支持构造、析构、成员函数、属性、重载操作符等。
- 用
pybind11::class_声明绑定类(m, "MyClass") -
.def(pybind11::init())绑定构造函数;.def("method", &MyClass::method)绑定成员函数 - 成员变量用
.def_readwrite("name", &MyClass::name);只读用def_readonly - 注意:C++ 对象生命周期由 Python 引用计数管理,除非显式用
pybind11::return_value_policy控制,否则默认按值返回会触发拷贝
真正容易被忽略的是 Python 解释器初始化状态——如果你在已有 Python 进程中(比如嵌入式场景)加载 pybind11 模块,确保 PyEval_InitThreads()(旧版)或 GIL 管理已就绪;而绝大多数情况(直接运行 python script.py)不需要操心这个。











