环境信息:

  1. $ lsb_release -a
  2. No LSB modules are available.
  3. Distributor ID: Ubuntu
  4. Description: Ubuntu 20.04.2 LTS
  5. Release: 20.04
  6. Codename: focal
  7. $ apt-get install python3-dev cmake g++

让我们首先为一个非常简单的函数创建Python绑定,该函数将两个数字相加并返回结果,为简单起见,我们将此功能和绑定代码都放入一个名为 example.cpp 的文件,其内容如下:

  1. #include <pybind11/pybind11.h>
  2. int add(int i, int j) {
  3. return i + j;
  4. }
  5. PYBIND11_MODULE(example, m) {
  6. m.doc() = "pybind11 example plugin"; // optional module docstring
  7. m.def("add", &add, "A function which adds two numbers");
  8. }

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

关键字参数

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

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

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

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

关键字名称也出现在文档内的功能签名中:

  1. help(example)
  2. ....
  3. FUNCTIONS
  4. add(...)
  5. Signature : (i: int, j: int) -> int
  6. A function which adds two numbers

也可以使用命名参数的简短表示法:

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

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

默认参数

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

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

默认值也出现在文档中。

  1. >>> help(example)
  2. ....
  3. FUNCTIONS
  4. add(...)
  5. Signature : (i: int = 1, j: int = 2) -> int
  6. A function which adds two numbers

速记符号也可用于默认参数:

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

导出变量

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

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

这些可以从Python访问:

  1. >>> import example
  2. >>> example.the_answer
  3. 42
  4. >>> example.what
  5. 'World'

支持的数据类型

开箱即用地支持大量数据类型,它们通常可以无缝用作函数参数,返回值或通常与 py::cast 一起使用。有关完整概述,请参见“类型转换”部分。