使用 Boost.Python 开发 Python 扩展:完整教程
Boost.Python 是 Boost C++ 库的一部分,专门用于将 C++ 代码暴露给 Python。作为 Python 扩展开发的经典解决方案,Boost.Python 提供了丰富的功能和良好的兼容性,特别适合大型 C++ 项目与 Python 的集成。
为什么选择 Boost.Python?
- 功能全面:提供从基础函数到复杂类的完整绑定支持
- 成熟稳定:Boost 库的一部分,经过长期测试和验证
- 兼容性好:支持广泛的 C++ 特性(包括 C++03、C++11、C++14等)
- 自动类型转换:支持 C++ 类型与 Python 类型的自动转换
- 强大的扩展能力:支持元编程、工厂模式等高级特性
Boost.Python 的历史与现状
Boost.Python 是最早的 C++ 到 Python 绑定库之一,它的设计理念强调完整性和稳定性。虽然现在有 PyBind11 这样的轻量级替代品,但 Boost.Python 在以下场景中仍然是理想选择:
- 已经使用 Boost 库的大型项目
- 需要与 Boost 其他组件深度集成的应用
- 对稳定性要求极高的企业级应用
- 需要支持旧版 C++ 标准的项目
环境准备
安装 Boost.Python
# Linux (Ubuntu/Debian)
sudo apt-get install libboost-python-dev
# macOS (Homebrew)
brew install boost-python3
# Windows (vcpkg)
vcpkg install boost-python
# 源码编译
# 从 https://www.boost.org/ 下载 Boost 源码
cd boost_1_82_0
./bootstrap.sh --with-python=/usr/bin/python3
./b2 install --with-python检查安装
# 简单的测试程序
import sys
import subprocess
# 检查 Boost.Python 是否可用
result = subprocess.run(['pkg-config', '--modversion', 'python3'],
capture_output=True, text=True)
print(f"Python version: {result.stdout.strip()}")项目结构
一个典型的 Boost.Python 项目结构如下:
boost_python_example/
├── CMakeLists.txt # CMake 配置
├── setup.py # Python 构建配置
├── src/
│ ├── hello.cpp # C++ 源码
│ ├── functions.cpp # 函数定义
│ └── classes.cpp # 类定义
├── include/
│ └── utils.h # C++ 头文件
└── test_example.py # 测试脚本基础实现
1. 简单函数绑定
创建 hello.cpp 文件:
#include <boost/python.hpp>
// 简单函数
int add(int a, int b) {
return a + b;
}
// 斐波那契数列
int fibonacci(int n) {
if (n == 0) return 0;
int a = 0, b = 1;
for (int i = 1; i < n; ++i) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
// 模块定义
BOOST_PYTHON_MODULE(hello) {
using namespace boost::python;
// 注册函数
def("add", add, "两个整数相加");
def("fibonacci", fibonacci, "计算斐波那契数列");
// 添加模块常量
scope().attr("version") = "1.0.0";
scope().attr("author") = "C++ Developer";
}2. 函数参数处理
#include <boost/python.hpp>
#include <string>
#include <vector>
using namespace boost::python;
// 默认参数
std::string greet(std::string name = "World") {
return "Hello, " + name + "!";
}
// 关键字参数
void print_info(std::string name, int age, std::string city = "Unknown") {
std::cout << "Name: " << name
<< ", Age: " << age
<< ", City: " << city << std::endl;
}
// 支持向量
double sum_vector(std::vector<double> const& vec) {
double total = 0.0;
for (double v : vec) {
total += v;
}
return total;
}
// 模块注册
BOOST_PYTHON_MODULE(functions) {
using namespace boost::python;
// 带默认参数的函数
def("greet", greet,
(arg("name") = "World"),
"打招呼函数");
// 带关键字参数的函数
def("print_info", print_info,
(arg("name"), arg("age"), arg("city") = "Unknown"),
"打印个人信息");
// 向量处理
def("sum_vector", sum_vector,
"计算向量中所有元素的和");
// 注册向量类型
class_<std::vector<double>>("DoubleVector")
.def("__len__", &std::vector<double>::size)
.def("clear", &std::vector<double>::clear)
.def("append", &std::vector<double>::push_back)
.def("__getitem__", +[](std::vector<double>& v, int i) -> double {
if (i < 0 || i >= v.size()) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
return v[i];
});
}3. 类定义
#include <boost/python.hpp>
#include <string>
using namespace boost::python;
class Counter {
private:
int count_;
std::string name_;
public:
// 构造函数
Counter(std::string name, int initial_value = 0)
: count_(initial_value), name_(name) {}
// 实例方法
int increment(int amount = 1) {
count_ += amount;
return count_;
}
int decrement(int amount = 1) {
count_ -= amount;
return count_;
}
// 属性访问
int get_count() const { return count_; }
void set_count(int value) { count_ = value; }
std::string get_name() const { return name_; }
// 字符串表示
std::string str() const {
return "Counter(name='" + name_ + "', count=" +
std::to_string(count_) + ")";
}
// 运算符重载
Counter operator+(Counter const& other) const {
return Counter(name_ + "+" + other.name_,
count_ + other.count_);
}
bool operator==(Counter const& other) const {
return count_ == other.count_ && name_ == other.name_;
}
};
// 类绑定
BOOST_PYTHON_MODULE(classes) {
using namespace boost::python;
class_<Counter>("Counter", init<std::string, optional<int>>())
.def(init<std::string, optional<int>>())
.def("increment", &Counter::increment,
(arg("amount") = 1),
"增加计数器值")
.def("decrement", &Counter::decrement,
(arg("amount") = 1),
"减少计数器值")
.add_property("count",
&Counter::get_count,
&Counter::set_count)
.add_property("name", &Counter::get_name)
.def("__str__", &Counter::str)
.def("__repr__", &Counter::str)
.def(self + self)
.def(self == self);
}4. 高级类特性
#include <boost/python.hpp>
#include <memory>
using namespace boost::python;
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
virtual std::string name() const = 0;
};
class Circle : public Shape {
private:
double radius_;
public:
Circle(double radius) : radius_(radius) {}
double area() const override {
return 3.14159 * radius_ * radius_;
}
std::string name() const override {
return "Circle";
}
double get_radius() const { return radius_; }
void set_radius(double radius) { radius_ = radius; }
};
class Rectangle : public Shape {
private:
double width_, height_;
public:
Rectangle(double width, double height)
: width_(width), height_(height) {}
double area() const override {
return width_ * height_;
}
std::string name() const override {
return "Rectangle";
}
double get_width() const { return width_; }
double get_height() const { return height_; }
};
// 工厂函数
std::shared_ptr<Shape> create_circle(double radius) {
return std::make_shared<Circle>(radius);
}
std::shared_ptr<Shape> create_rectangle(double width, double height) {
return std::make_shared<Rectangle>(width, height);
}
// 多态绑定
BOOST_PYTHON_MODULE(shapes) {
using namespace boost::python;
// 基类绑定
class_<Shape, std::shared_ptr<Shape>, boost::noncopyable>("Shape", no_init)
.def("area", pure_virtual(&Shape::area))
.def("name", pure_virtual(&Shape::name));
// 派生类绑定
class_<Circle, bases<Shape>, std::shared_ptr<Circle>>("Circle", init<double>())
.def("get_radius", &Circle::get_radius)
.def("set_radius", &Circle::set_radius);
class_<Rectangle, bases<Shape>, std::shared_ptr<Rectangle>>("Rectangle", init<double, double>())
.def("get_width", &Rectangle::get_width)
.def("get_height", &Rectangle::get_height);
// 工厂函数
def("create_circle", create_circle);
def("create_rectangle", create_rectangle);
}5. 枚举类型
#include <boost/python.hpp>
using namespace boost::python;
enum Status {
Pending,
Running,
Completed,
Failed
};
enum class Color {
Red,
Green,
Blue
};
BOOST_PYTHON_MODULE(enums) {
using namespace boost::python;
// C 风格枚举
enum_<Status>("Status")
.value("Pending", Pending)
.value("Running", Running)
.value("Completed", Completed)
.value("Failed", Failed);
// C++11 枚举类
enum_<Color>("Color")
.value("Red", Color::Red)
.value("Green", Color::Green)
.value("Blue", Color::Blue);
}6. 异常处理
#include <boost/python.hpp>
#include <stdexcept>
using namespace boost::python;
class CustomError : public std::runtime_error {
public:
CustomError(int code, std::string const& message)
: std::runtime_error(message), code_(code) {}
int get_code() const { return code_; }
private:
int code_;
};
int risky_operation(int code) {
if (code < 0) {
throw CustomError(code, "Invalid code");
}
return code * 10;
}
// 翻译异常
void translate_custom_error(CustomError const& e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
}
BOOST_PYTHON_MODULE(exceptions) {
using namespace boost::python;
// 注册自定义异常
class_<CustomError, bases<std::runtime_error>>("CustomError", no_init)
.def("get_code", &CustomError::get_code);
// 注册异常翻译器
register_exception_translator<CustomError>(&translate_custom_error);
def("risky_operation", risky_operation,
"可能抛出异常的操作");
}7. 迭代器
#include <boost/python.hpp>
#include <boost/python/iterator.hpp>
using namespace boost::python;
class FibonacciIterator {
private:
int current_, next_, max_iterations_, iteration_;
public:
FibonacciIterator(int max_iterations)
: current_(0), next_(1),
max_iterations_(max_iterations), iteration_(0) {}
int next() {
if (iteration_ >= max_iterations_) {
PyErr_SetString(PyExc_StopIteration, "No more items");
throw_error_already_set();
}
int result = current_;
int temp = current_;
current_ = next_;
next_ = temp + next_;
iteration_ += 1;
return result;
}
};
BOOST_PYTHON_MODULE(iterators) {
using namespace boost::python;
class_<FibonacciIterator>("FibonacciIterator", init<int>())
.def("__iter__", +[](FibonacciIterator& self) -> FibonacciIterator& {
return self;
})
.def("__next__", &FibonacciIterator::next);
}8. 回调函数
#include <boost/python.hpp>
#include <functional>
using namespace boost::python;
int apply_callback(object const& callback, int value) {
// 调用 Python 函数
object result = callback(value * 2);
return extract<int>(result);
}
std::vector<int> map_with_callback(
std::vector<int> const& list,
object const& callback) {
std::vector<int> result;
result.reserve(list.size());
for (int item : list) {
object python_result = callback(item);
int converted_result = extract<int>(python_result);
result.push_back(converted_result);
}
return result;
}
BOOST_PYTHON_MODULE(callbacks) {
using namespace boost::python;
def("apply_callback", apply_callback,
"应用回调函数");
def("map_with_callback", map_with_callback,
"对列表中的每个元素应用回调函数");
}构建配置
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(boost_python_example)
# 查找 Python
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
find_package(Boost REQUIRED COMPONENTS python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
# 包含目录
include_directories(
${Python3_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# 创建 Python 模块
add_library(hello MODULE src/hello.cpp)
target_link_libraries(hello
PRIVATE
Boost::python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}
Python3::Python)
# 设置模块输出名称
set_target_properties(hello PROPERTIES PREFIX "" SUFFIX ".so")
# 添加更多模块
add_library(functions MODULE src/functions.cpp)
target_link_libraries(functions
PRIVATE
Boost::python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}
Python3::Python)
set_target_properties(functions PROPERTIES PREFIX "" SUFFIX ".so")
# 安装位置
install(TARGETS hello functions DESTINATION lib)setup.py(替代方案)
from setuptools import setup, Extension
from distutils.command.build_ext import build_ext
import sys
class BuildExt(build_ext):
def build_extension(self, ext):
# Boost.Python 需要特殊处理
ext.include_dirs.append('/usr/include')
ext.library_dirs.append('/usr/lib')
ext.libraries.append('boost_python3')
ext.libraries.append('python3')
super().build_extension(ext)
ext_modules = [
Extension(
'hello',
['src/hello.cpp'],
include_dirs=['/usr/include'],
library_dirs=['/usr/lib'],
libraries=['boost_python3', 'python3'],
extra_compile_args=['-std=c++11', '-fPIC'],
language='c++',
),
]
setup(
name='boost_python_example',
ext_modules=ext_modules,
cmdclass={'build_ext': BuildExt},
zip_safe=False,
)构建和安装
# 使用 CMake
mkdir build && cd build
cmake .. -DPYTHON_EXECUTABLE=$(which python3)
cmake --build .
# 模块会生成在 build/ 目录下
# 使用 setuptools
pip install .
# 直接编译
g++ -shared -fPIC -o hello.so src/hello.cpp \
-I/usr/include/python3.8 \
-I/usr/include \
-lboost_python3 \
-lpython3.8性能优化技巧
1. 减少 Python/C++ 边界穿越
// 避免:频繁的边界穿越
object process_list_slow(object const& list) {
// 每次循环都有边界穿越
for (int i = 0; i < len(list); ++i) {
// ...
}
}
// 推荐:批量处理
object process_list_fast(object const& list) {
// 提取到 C++ 容器
std::vector<double> vec;
for (int i = 0; i < len(list); ++i) {
vec.push_back(extract<double>(list[i]));
}
// 在 C++ 中批量处理
for (auto& v : vec) {
v *= 2.0;
}
// 返回结果
list result;
for (auto v : vec) {
result.append(v);
}
return result;
}2. 使用引用和指针
// 使用引用避免复制
double process_reference(std::vector<double> const& data) {
double sum = 0.0;
for (auto const& v : data) {
sum += v;
}
return sum;
}
// 使用智能指针
std::shared_ptr<LargeObject> create_large_object() {
return std::make_shared<LargeObject>();
}3. 内存管理优化
class MemoryEfficient {
private:
std::unique_ptr<double[]> data_;
size_t size_;
public:
MemoryEfficient(size_t size)
: size_(size), data_(std::make_unique<double[]>(size)) {}
// 避免不必要的内存分配
void process_in_place() {
for (size_t i = 0; i < size_; ++i) {
data_[i] *= 2.0;
}
}
};与其他扩展方案对比
Boost.Python vs PyBind11
| 特性 | Boost.Python | PyBind11 |
|---|---|---|
| 核心设计 | Boost 库的一部分 | 轻量级头文件库 |
| 依赖关系 | 需要完整的 Boost | 只有头文件,无运行时依赖 |
| 构建复杂度 | 较高(需要 Boost) | 较低 |
| 性能 | 优秀 | 极佳 |
| C++ 标准支持 | C++03 及以上 | C++11 及以上 |
| 学习曲线 | 中等 | 较低 |
| 社区支持 | 成熟稳定 | 活跃发展 |
Boost.Python vs Cython
| 特性 | Boost.Python | Cython |
|---|---|---|
| 语言 | C++ | Python 超集 |
| 语法复杂度 | C++ 语法 | Python 语法 |
| 性能 | 接近原生 C++ | 较高(编译为 C) |
| 内存管理 | 手动管理 | 手动管理 |
| 调试难度 | 中等 | 困难 |
| 适用场景 | C++ 项目集成 | Python 代码优化 |
Boost.Python vs PyO3
| 特性 | Boost.Python | PyO3 |
|---|---|---|
| 语言 | C++ | Rust |
| 内存安全 | 手动管理 | 编译时保证 |
| 现代特性 | 经典 C++ | 现代化语言特性 |
| 构建工具 | CMake/Boost.Build | Cargo/maturin |
| 性能 | 优秀 | 极佳 |
| 学习曲线 | 中等(需 C++) | 中等(需 Rust) |
最佳实践
1. 模块设计
// 良好的模块设计
namespace math {
double sqrt(double x);
double pow(double base, double exponent);
}
namespace geometry {
class Point { /* ... */ };
class Circle { /* ... */ };
}
// 分别暴露不同的命名空间
BOOST_PYTHON_MODULE(mylib) {
using namespace boost::python;
// 创建子模块
object math_module(handle<>(borrowed(PyImport_AddModule("mylib.math"))));
scope().attr("math") = math_module;
scope math_scope = math_module;
// 在 math 子模块中注册函数
math_scope.def("sqrt", math::sqrt);
math_scope.def("pow", math::pow);
}2. 错误处理
// 统一的错误处理
template<typename Func>
object safe_call(Func func) {
try {
return func();
} catch (std::exception const& e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
throw_error_already_set();
} catch (...) {
PyErr_SetString(PyExc_RuntimeError, "Unknown error");
throw_error_already_set();
}
return object(); // 永远不会执行
}
// 使用包装器
BOOST_PYTHON_MODULE(safe_module) {
using namespace boost::python;
def("safe_operation", +[](int value) -> object {
return safe_call([value]() -> object {
if (value < 0) {
throw std::runtime_error("Negative value");
}
return object(value * 2);
});
});
}3. 文档注释
// 详细的文档注释
class DocumentedClass {
public:
/// @brief 创建一个新的实例
/// @param name 实例名称
/// @param value 初始值
DocumentedClass(std::string name, int value = 0);
/// @brief 执行重要操作
/// @param factor 操作因子
/// @return 操作结果
int important_operation(double factor);
};
BOOST_PYTHON_MODULE(documented) {
using namespace boost::python;
class_<DocumentedClass>("DocumentedClass",
"这是一个详细文档化的类",
init<std::string, optional<int>>())
.def("important_operation", &DocumentedClass::important_operation,
"执行重要操作",
arg("factor"));
}实际应用场景
1. 科学计算库
// 数值计算库绑定
class Matrix {
private:
std::vector<std::vector<double>> data_;
public:
Matrix(size_t rows, size_t cols);
Matrix operator*(Matrix const& other) const;
Matrix transpose() const;
double determinant() const;
};
// 暴露线性代数功能
BOOST_PYTHON_MODULE(linalg) {
using namespace boost::python;
class_<Matrix>("Matrix", init<size_t, size_t>())
.def("__mul__", &Matrix::operator*)
.def("transpose", &Matrix::transpose)
.def("det", &Matrix::determinant);
}2. 游戏引擎绑定
// 游戏对象绑定
class GameObject {
public:
virtual void update(double delta_time) = 0;
virtual void render() = 0;
};
class Sprite : public GameObject {
public:
void update(double delta_time) override;
void render() override;
void set_position(double x, double y);
void set_scale(double scale);
};
// 游戏引擎接口
BOOST_PYTHON_MODULE(game) {
using namespace boost::python;
class_<GameObject, boost::noncopyable>("GameObject", no_init)
.def("update", pure_virtual(&GameObject::update))
.def("render", pure_virtual(&GameObject::render));
class_<Sprite, bases<GameObject>>("Sprite")
.def("set_position", &Sprite::set_position)
.def("set_scale", &Sprite::set_scale);
}3. 金融计算
// 金融计算引擎
class OptionPricing {
public:
double black_scholes(double S, double K, double r,
double sigma, double T, bool is_call);
double monte_carlo_pricing(double S, double K, double r,
double sigma, double T, int simulations);
};
BOOST_PYTHON_MODULE(finance) {
using namespace boost::python;
class_<OptionPricing>("OptionPricing")
.def("black_scholes", &OptionPricing::black_scholes)
.def("monte_carlo_pricing", &OptionPricing::monte_carlo_pricing);
}迁移策略
从纯 C++ 迁移到 Boost.Python
- 识别接口:确定需要暴露给 Python 的类和函数
- 创建绑定:使用 Boost.Python 包装 C++ 代码
- 测试兼容性:确保 Python 接口正常工作
- 性能优化:优化边界穿越的性能开销
- 文档化:为 Python 接口编写文档
从其他绑定库迁移
// 从 SWIG 迁移到 Boost.Python 的示例
// SWIG 接口文件 (.i)
%module example
%{
#include "example.h"
%}
%include "example.h"
// Boost.Python 等价代码
#include <boost/python.hpp>
#include "example.h"
BOOST_PYTHON_MODULE(example) {
using namespace boost::python;
// 绑定 example.h 中的内容
// ...
}总结
Boost.Python 作为经典的 C++ 到 Python 绑定库,提供了强大而完整的功能集。虽然它在某些方面不如 PyBind11 轻量,但对于已经使用 Boost 库的项目或需要高级功能的应用来说,Boost.Python 仍然是优秀的选择。
关键优势:
- 功能全面:支持从基础类型到复杂继承的所有特性
- 稳定性高:作为 Boost 库的一部分,经过了严格的测试
- 社区支持:拥有庞大的用户基础和丰富的文档
- 向后兼容:支持旧版 C++ 标准
适用场景:
- ✅ 已经使用 Boost 库的项目
- ✅ 需要高级特性(如多继承、元编程)的应用
- ✅ 对稳定性要求极高的企业级应用
- ✅ 需要支持旧版 C++ 标准的项目
学习资源:
无论你是要将现有的 C++ 库暴露给 Python,还是要为 Python 应用开发高性能扩展,Boost.Python 都是一个值得考虑的优秀选择。