pybind11 初探

2020/10/10 pybind11python-cppCombining

官方文档的入门教程 (opens new window)

# 安装

直接利用 conda 安装

conda install pybind11 -c conda-forge
1

# 头文件和名称空间的约定

#include <pybind11/pybind11.h>

namespace py = pybind11;
1
2
3

# 为简单函数创建绑定

首先,为一个非常简单的函数创建 Python 绑定,该函数将两个数字相加并返回其结果:

int add(int i, int j) {
    return i + j;
}
1
2
3
PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring

    m.def("add", &add, "A function which adds two numbers");
}
1
2
3
4
5

PYBIND11_MODULE() 宏创建一个函数,当从 Python 内部发出 import 语句时将调用该函数。 模块名称(example)作为第一个宏参数给出(不应使用引号引起来)。 第二个参数(m)定义了 py::module_ 类型的变量,该变量是用于创建绑定的主要接口。 方法 module_::def() 生成将 add() 函数公开给 Python 的绑定代码。

::: Note 请注意,将我们的函数公开给 Python 所需的代码很少: 有关该函数的参数和返回值的所有详细信息都是使用模板元编程自动推断的。 尽管底层实现有很大的不同,但总体方法和使用的语法是从 Boost.Python 借鉴的。 :::

# 关键字参数

通过简单的代码修改,就可以指定 Python 的参数名称(在这种情况下为 ij)。

m.def("add", &add, "A function which adds two numbers",
      py::arg("i"), py::arg("j"));
1
2

arg 是可用于将元数据传递到 module_::def() 的几种特殊标记类之一。 通过修改后的绑定代码,我们现在可以使用关键字参数来调用函数,这是更具可读性的替代方法,特别是对于带有许多参数的函数:

>>> import example
>>> example.add(i=1, j=2)
3L
1
2
3

关键字名字也出现在文档内的函数注释中。

>>> help(example)

....

FUNCTIONS
    add(...)
        Signature : (i: int, j: int) -> int

        A function which adds two numbers
1
2
3
4
5
6
7
8
9

也可以使用命名参数的缩写形式:

// regular notation
m.def("add1", &add, py::arg("i"), py::arg("j"));
// shorthand
using namespace pybind11::literals;
m.def("add2", &add, "i"_a, "j"_a);
1
2
3
4
5

后缀 _a 构成一个 C++11 字,它等效于 arg。 请注意,必须首先声明 using namespace pybind11::literals 才可使用 _a。 除了 _a 之外,这没有从 pybind11 命名空间引入任何其他内容。

# 默认参数

现在假设要绑定的函数具有默认参数,例如:

int add(int i = 1, int j = 2) {
    return i + j;
}
1
2
3

遗憾的是, pybind11 无法自动提取这些参数,因为它们不是函数类型信息的一部分。但是,使用 arg 扩展名可以很容易地指定它们:

m.def("add", &add, "A function which adds two numbers",
      py::arg("i") = 1, py::arg("j") = 2);
1
2

默认值也出现在文档中。

help(example)

....

FUNCTIONS
    add(...)
        Signature : (i: int = 1, j: int = 2) -> int

        A function which adds two numbers
1
2
3
4
5
6
7
8
9

# 导出变量

要从 C++ 暴露值,请使用 attr 函数将其注册到模块中,如下所示。内置类型和常规对象(稍后会详细介绍)在分配为属性时会自动进行转换,并且可以使用 py::cast 函数进行显式转换。

PYBIND11_MODULE(example, m) {
    m.attr("the_answer") = 42;
    py::object world = py::cast("World");
    m.attr("what") = world;
}
1
2
3
4
5

这些可以从 Python 访问:

import example
example.the_answer
42
example.what
'World'
1
2
3
4
5
Last Updated: 2023-10-29T08:26:04.000Z