Skip to content

PyBind11 基础绑定

为了高效,现代化的绑定C++代码到Python,PyBind11框架是一个非常流行的选择。它提供了简洁的语法和强大的功能,使得C++与Python之间的交互变得简单而高效。

安装 PyBind11

在开始之前,确保你已经安装了PyBind11。

1. 使用Pip安装

安装到当前环境:

bash
pip install pybind11

安装到系统全局(可被CMAKE直接搜索):

bash
pip install "pybind11[global]"

2. 手动配置

  1. 手动克隆PyBind11仓库:
bash
git clone https://github.com/pybind/pybind11.git
  1. 在 CMake 项目中引入 PyBind11:
cmake
add_subdirectory({path}/pybind11)

编写 CMakeLists.txt

创建一个 CMakeLists.txt 文件来配置你的项目。以下是一个基本的示例:

cmake
cmake_minimum_required (VERSION 3.11)

project(PYTHON_TEST)

if(MSVC)
    add_compile_options(/utf-8 /EHsc)
endif()

# 启用pybind11的Python自动查找功能,避免人为指定路径。
set(PYBIND11_FINDPYTHON ON)

# 查找pybind11包(pip install "pybind11[global]" 后才能直接 find_package)
find_package(pybind11 CONFIG REQUIRED)

# 如果手动配置了pybind11则可以直接使用 无需find_package
# add_subdirectory({path}/pybind11)

# 创建Python扩展模块(该函数由pybind11提供,本质是add_library的封装)
# 生成的 testLib 会是 testLib.pyd (Windows) 或 testLib.so (Linux)
pybind11_add_module(testLib main.cpp)

# 可选:直接安装到 Python site-packages (个人不推荐这种污染全局环境的行为)
# install(TARGETS testLib DESTINATION ${Python_SITEARCH})

set_property(TARGET testLib PROPERTY CXX_STANDARD 20)

编写绑定代码

创建一个 main.cpp 文件,编写你的C++代码并使用PyBind11进行绑定。

cpp
#include <iostream>
#include <pybind11/pybind11.h>

namespace py = pybind11;    // 简化命名空间

// 一个简单的C++函数
static int add(int a, int b)
{
    return a + b;
}

// Python有特定的入口函数搜索规则:文件名必须与模块名相同
// 使用 PYBIND11_MODULE 宏来简化并定义模块
PYBIND11_MODULE(testLib, m)
{
    m.doc() = "这是一个绑定测试库"; // 模块的__doc__文档属性

    // pybind11通过模板元编程技术自动识别类型信息并生成绑定代码完成绑定
    m.def("add", &add, "基础函数测试");
}

以上代码编译后将生成的.pyd文件放置在python项目内/配置到解释器环境库中即可使用。

  • 代码测试
python
import testLib  # 确保可以搜索到目标pyd文件

print(testLib.add(10000, 2000)) # -> 正常输出计算结果

STD类型绑定

PyBind11支持直接绑定许多标准库类型,以下是一个绑定std::stringstd::vector<int>的示例:

cpp
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>     // 支持 std::string, std::vector 等STD类型转换

namespace py = pybind11;

// 计算并返回命名空间部分字符串
static std::string getNameSpace(const std::string& str)
{
    // pybind11会自动解析Python字符串并构造std::string传入(产生至少一次拷贝)
    auto pos = str.find(':');
    if (pos != std::string::npos)
    {
        return str.substr(0, pos);
    }
    return "";
}

// 按空格拆分字符串为单词列表
static std::vector<std::string> splitBySpace(const std::string& str)
{
    std::vector<std::string> result;
    std::istringstream iss(str);
    std::string token;
    while (iss >> token)
    {
        result.push_back(token);
    }
    // pybind11会自动将std::vector解析并构造为Python的list返回
    return result;
}

PYBIND11_MODULE(testLib, m)
{
    m.doc() = "这是一个绑定测试库";

    m.def("getNameSpace", &getNameSpace, "命名空间计算");

    m.def("splitBySpace", &splitBySpace, "字符串拆分");

    // 除了直接绑定函数指针,还可以绑定lambda对象
    m.def("greet", [] (const std::string& name)
    {
        return "Hello, " + name + "!";
    },
    "一个简单的问候函数");
}

默认形参处理

PyBind11支持为绑定的函数指定默认参数值。以下是一个示例:

cpp
#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;

static void testArgs(int a, int b = 10, const std::string& msg = "默认参数")
{
    std::cout << "a: " << a << ", b: " << b << ", msg: " << msg << "\n";
}

PYBIND11_MODULE(testLib, m)
{
    m.doc() = "这是一个绑定测试库";

    // 使用 py::arg 指定参数名和默认值 由pybind11自动处理
    m.def("testArgs", &testArgs, py::arg("a"), py::arg("b") = 10, py::arg("msg") = "默认参数", "函数参数测试");
}

异常处理

PyBind11允许你在C++代码中抛出异常,并将其转换为Python异常。以下是一个示例:

cpp
#include <iostream>
#include <pybind11/pybind11.h>
#include <functional>

namespace py = pybind11;

static void testErr1()
{
    throw std::runtime_error("抛出异常,pybind11会捕获并转换为Python异常");
}

// pybind11可以直接将Python函数转换为std::function传入C++
static void testErr2(const std::function<void()>& func)
{
    try
    {
        func(); // 调用传入的Python函数
    }
    catch (const std::exception& e)
    {
        std::cerr << "捕获到Python异常: " << e.what() << "\n";
    }
}

PYBIND11_MODULE(testLib, m)
{
    m.doc() = "这是一个绑定测试库";

    m.def("testErr1", &testErr1, "CPP抛出异常测试");
    m.def("testErr2", &testErr2, "CPP捕获Python异常测试");
}

总结

PyBind11是一个强大且易于使用的C++绑定库,适合将C++代码集成到Python项目中。通过上述示例,你可以快速上手并创建自己的Python扩展模块。更多高级功能和用法,请参考官方文档

Released under the BSD3 License