环境信息:
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
$ apt-get install python3-dev cmake g++
让我们首先为一个非常简单的函数创建Python绑定,该函数将两个数字相加并返回结果,为简单起见,我们将此功能和绑定代码都放入一个名为 example.cpp
的文件,其内容如下:
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers");
}
PYBIND11_MODULE()
宏创建一个函数,当从 Python 内部发出 import
语句时将调用该函数。 模块名称(示例)作为第一个宏参数给出(不应使用引号引起来);第二个参数 m
定义了 py::module_
类型的变量,该变量是用于创建绑定的主要接口。 方法 module_::def()
生成将 add()
函数公开给Python的绑定代码。
关键字参数
通过简单的代码修改,就可以通知Python参数名称(在这种情况下为 i
和 j
)。
m.def("add", &add, "A function which adds two numbers",
py::arg("i"), py::arg("j"));
arg
是可用于将元数据传递到 module_::def()
的几种特殊标记类之一。 使用此修改后的绑定代码,我们现在可以使用关键字参数来调用函数,这是一种更具可读性的替代方法,特别是对于带有许多参数的函数:
import example
example.add(i=1, j=2)
3L
关键字名称也出现在文档内的功能签名中:
help(example)
....
FUNCTIONS
add(...)
Signature : (i: int, j: int) -> int
A function which adds two numbers
也可以使用命名参数的简短表示法:
// 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);
后缀 _a
构成一个C++11 字面量,它等效于 arg
。 请注意,必须首先通过使用引入命名空间 using namespace pybind11::literals
使 _a
运算符可见。 除了文字之外,这没有从 pybind11
命名空间引入任何其他内容。
默认参数
现在假设要绑定的函数具有默认参数,例如:
int add(int i = 1, int j = 2) {
return i + j;
}
默认值也出现在文档中。
>>> help(example)
....
FUNCTIONS
add(...)
Signature : (i: int = 1, j: int = 2) -> int
A function which adds two numbers
速记符号也可用于默认参数:
// regular notation
m.def("add1", &add, py::arg("i") = 1, py::arg("j") = 2);
// shorthand
m.def("add2", &add, "i"_a=1, "j"_a=2);
导出变量
要从C++公开值,请使用 attr
函数将其注册到模块中,如下所示。 内置类型和通用对象(稍后会详细介绍)在分配为属性时会自动进行转换,并且可以使用 py::cast
函数进行显式转换。
PYBIND11_MODULE(example, m) {
m.attr("the_answer") = 42;
py::object world = py::cast("World");
m.attr("what") = world;
}
这些可以从Python访问:
>>> import example
>>> example.the_answer
42
>>> example.what
'World'
支持的数据类型
开箱即用地支持大量数据类型,它们通常可以无缝用作函数参数,返回值或通常与 py::cast
一起使用。有关完整概述,请参见“类型转换”部分。