pybind11 的应用
pybind11
是一个轻量级的 C++ 库,用于将 C++ 代码暴露给 Python 调用,或者反过来在 C++ 中调用 Python 代码。它比传统的 Boost.Python
更简洁高效,适用于现代 C++(C++11 及以上)。以下是 pybind11
的基本使用方法:
1. 安装 pybind11
可以通过 pip
安装:
pip install pybind11
或者从源码安装(推荐):
git clone https://github.com/pybind/pybind11.git cd pybind11 mkdir build && cd build cmake .. make install
2. 基本用法:C++ 暴露给 Python
示例 1:简单函数绑定
// example.cpp #include <pybind11/pybind11.h>int add(int a, int b) {return a + b; }PYBIND11_MODULE(example, m) {m.def("add", &add, "A function that adds two numbers"); }
编译(Linux/macOS)
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
编译(Windows, MSVC)
cl /EHsc /LD /I C:\path\to\Python\include /I C:\path\to\pybind11\include example.cpp /link /LIBPATH:C:\path\to\Python\libs
在 Python 中调用
import example print(example.add(2, 3)) # 输出 5
示例 2:绑定 C++ 类
// example_class.cpp #include <pybind11/pybind11.h>class MyClass { public:MyClass(int value) : value_(value) {}void setValue(int v) { value_ = v; }int getValue() const { return value_; } private:int value_; };PYBIND11_MODULE(example_class, m) {pybind11::class_<MyClass>(m, "MyClass").def(pybind11::init<int>()).def("setValue", &MyClass::setValue).def("getValue", &MyClass::getValue); }
编译(同上)
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example_class.cpp -o example_class$(python3-config --extension-suffix)
在 Python 中调用
import example_class obj = example_class.MyClass(10) print(obj.getValue()) # 输出 10 obj.setValue(20) print(obj.getValue()) # 输出 20
3. Python 调用 C++ 的高级用法
(1) 支持 NumPy 数组(pybind11/numpy.h
)
#include <pybind11/pybind11.h> #include <pybind11/numpy.h>namespace py = pybind11;py::array_t<double> add_arrays(py::array_t<double> a, py::array_t<double> b) {py::buffer_info a_buf = a.request(), b_buf = b.request();auto result = py::array_t<double>(a_buf.size);py::buffer_info res_buf = result.request();double *a_ptr = static_cast<double *>(a_buf.ptr);double *b_ptr = static_cast<double *>(b_buf.ptr);double *res_ptr = static_cast<double *>(res_buf.ptr);for (size_t i = 0; i < a_buf.size; i++) {res_ptr[i] = a_ptr[i] + b_ptr[i];}return result; }PYBIND11_MODULE(numpy_example, m) {m.def("add_arrays", &add_arrays, "Add two NumPy arrays"); }
Python 调用
import numpy as np import numpy_examplea = np.array([1.0, 2.0, 3.0]) b = np.array([4.0, 5.0, 6.0]) print(numpy_example.add_arrays(a, b)) # 输出 [5.0, 7.0, 9.0]
(2) 在 C++ 中调用 Python 代码
#include <pybind11/embed.h> // 必须包含这个头文件 #include <iostream>namespace py = pybind11;int main() {py::scoped_interpreter guard{}; // 启动 Python 解释器py::module sys = py::module::import("sys");py::print(sys.attr("path")); // 打印 Python 路径py::module math = py::module::import("math");float root = math.attr("sqrt")(2.0).cast<float>();std::cout << "sqrt(2) = " << root << std::endl;return 0; }
编译 & 运行
g++ -std=c++11 -I/usr/include/python3.8 -lpython3.8 call_python.cpp -o call_python ./call_python
sqrt(2) = 1.41421
4. 使用 CMake 管理项目
cmake_minimum_required(VERSION 3.4) project(example)find_package(pybind11 REQUIRED) # 需要 pybind11 已安装pybind11_add_module(example example.cpp) # 编译为 Python 模块
编译
mkdir build && cd build cmake .. make
生成的 .so
或 .pyd
文件可以直接在 Python 中导入。
5. 常见问题
(1) 如何传递 STL 容器?
pybind11
自动支持 std::vector
、std::map
等:
#include <pybind11/stl.h> // 必须包含这个头文件std::vector<int> process_vec(const std::vector<int>& v) {std::vector<int> result;for (int x : v) result.push_back(x * 2);return result; }PYBIND11_MODULE(stl_example, m) {m.def("process_vec", &process_vec); }
Python 调用:
import stl_example print(stl_example.process_vec([1, 2, 3])) # 输出 [2, 4, 6]
(2) 如何暴露 C++ 异常?
#include <stdexcept>void risky_func(int x) {if (x < 0) throw std::runtime_error("x must be >= 0"); }PYBIND11_MODULE(exception_example, m) {m.def("risky_func", &risky_func); }
Python 调用:
import exception_example try:exception_example.risky_func(-1) except RuntimeError as e:print(e) # 输出 "x must be >= 0"
总结
功能 | 方法 |
---|---|
C++ 函数暴露给 Python | m.def("func_name", &func) |
C++ 类暴露给 Python | pybind11::class_<MyClass>(m, "MyClass") |
支持 NumPy | #include <pybind11/numpy.h> |
C++ 调用 Python | py::scoped_interpreter{} + py::module::import |
STL 容器支持 | #include <pybind11/stl.h> |
异常处理 | 直接抛出 std::exception |
pybind11
是 C++/Python 互操作的高效工具,适用于高性能计算、机器学习等领域。