简介
PyBind11是能够让C++和Python代码之间相互调用的轻量级头文件库。在这之前已经有了一个类似功能的库:Boost.Python。既然已经有了一个类似库,而且PyBind11的目的和语法都与Boost.Python相似,为什么还要重复造轮子?原因主要有以下亮点:
- Boost.Python为了兼容大多数C++标准和编译器,它使用了很多可以说是魔法的操作去解决问题而变得非常的臃肿;
- 目前很多编译器对C++11已经有很好的支持,而且C++11应用也比较广泛。
因此,PyBind11应运而生,他能在抛弃Boost.Python的负担同时又具备Boost.Python的简单操作。
使用
PyBind11的主要目的是将已有的C++代码接口暴露给Python去调用。例如,ONNX Runtime --一个用于ONNX格式的神经网络模型推理的引擎,其推理的核心模块是用C++写的,但是从易用性、Python AI 方面的主导地位等方面考虑,它需要将模型推理的接口暴露给Python。在之前的文章ONNX Runtime 源码阅读:模型推理过程概览中也有提到过。其接口暴露代码在$ONNX_RUNTIME/onnxruntime/python/onnxruntime_pybind_state.cc中。
将C++暴露给Python主要有两个大方向:
- 将函数暴露给Python;
- 将类暴露给Python.
暴露函数
例如,我们已经有了一个C++函数实现了一个算法,代码存放在一个名字叫existence.h
的头文件中,Python想直接调用它。
using namespace std;
int add(int arg1, int arg2) {
cout<< "value of arg1 is : " << arg1 << endl;
return arg1 + arg2;
}
那么只需要将PyBind11的一个头文件包含并使用宏PYBIND11_MODULE
,简单几句话就能实现我们的目的:
#include "existence.h"
#include <pybind11/pybind11.h>
PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers");
}
在上面例子中,我们在使用宏的时候给了两个宏参数:example
和m
,其中example
是你给你的模块其的名字,m
其实是一个pybind11::module
类的一个实例,这是怎么做到的呢?下次有机会在解释。现在我们知道,使用pybind11::module
的方法def
就能将函数暴露,或者说,在名字叫example
的Python模块定义了一个函数。
当然,目前只是向模块添加了一个函数,我们还希望它表现的像直接用Python写的一个函数。什么意思呢?我们知道,在Python中定义一个函数,在指定它的参数的时候,可以是关键字参数、指定参数默认值,特别是参数多的时候,