简介 PyBind11
的主要目的是将已有的C++代码接口暴露给Python去调用。
使用者:
环境配置 macOS 1 2 3 # python3.7 brew install python3 python3 -m pip install pybind11
下载其他python
版本:官方下载
Ubuntu
系统版本:18.04
1 sudo apt-get -y install python3 python3-dev python3-pip
CentOS
系统版本:7.5
Win 官方下载
设置环境变量:
Q&A fatal error: ‘Python.h’ file not found 1 2 3 4 5 # centos yum install python3-devel # 将会安装至 /usr/include # ubuntu echo "export C_INCLUDE_PATH=${C_INCLUDE_PATH}:/usr/include/python3.6" >> ~/.bashrc echo "export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}:/usr/include/python3.6" >> ~/.bashrc
亦或是在 CMakeLists.txt
中包含
1 2 include_directories (SYSTEM /usr/include /python3.6 m)include_directories (SYSTEM /usr/local/include /python3.6 m)
ImportError: libSM.so.6: cannot open shared object file: No such file or directory 1 2 3 4 # ubuntu apt-get install libsm6 libxrender1 libxext-dev # centos yum install libXext libSM libXrender
使用 前置
工欲善其事,必先利其器。
将 C++ 暴露给 Python 主要由两个方向:
将 函数
暴露给 Python
将 类
暴露给 Python
暴露函数 普通函数 C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include "pybind11/pybind11.h" namespace py = pybind11;int add (int l, int r) { std ::cout << "compute " << l << " + " << r << " :" << std ::endl ; return l + r; } PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; m.def("add" , &add, "a function which adds two numbers." , py::arg("l" ) = 1 , py::arg("r" ) = 2 ); }
Python测试代码:
1 2 3 4 import compute_pybind_state as CXXprint(CXX.add(2 , 5 ))
匿名函数 C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include "pybind11/pybind11.h" namespace py = pybind11;PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; m.def( "sub" , [](int l, int r) { std ::cout << "compute " << l << " - " << r << " :" << std ::endl ; return l - r; }, "a function which one sub another." , py::arg("l" ) = 2 , py::arg("r" ) = 1 ); }
Python测试代码:
1 2 3 4 import compute_pybind_state as CXXprint(CXX.sub(3 , 1 ))
模板函数 C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include "pybind11/pybind11.h" namespace py = pybind11;template <typename T>T square (T x) { return x * x; }PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; m.def("square" , &square<double >); m.def("square" , &square<float >); m.def("square" , &square<int >); }
Python测试代码:
1 2 3 4 5 import compute_pybind_state as CXXprint(CXX.square(2 )) print(CXX.square(2.2 ))
重载函数 pybind11::overload_cast
只需要制定输入参数的类型,函数的返回值类型会自动推断 。
注意,该方法仅限于 C++14
及其以上版本方可支持。
C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include "pybind11/pybind11.h" namespace py = pybind11;int sub (int l, int r) { std ::cout << "compute int " << l << " - " << r << " :" << std ::endl ; return l - r; } float sub (float l, float r) { std ::cout << "compute float " << l << " - " << r << " :" << std ::endl ; return l - r; } PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; m.def("sub" , py::overload_cast<int , int >(&sub), "a function which int numbers sub another." , py::arg("l" ) = 3 , py::arg("r" ) = 2 ); m.def("sub" , py::overload_cast<float , float >(&sub), "a function which float numbers sub another." , py::arg("l" ) = 3.0f , py::arg("r" ) = 2.0f ); }
Python测试代码:
1 2 3 4 5 import compute_pybind_state as CXXprint(CXX.sub(3 , 2 )) print(CXX.sub(5.2 , 2.1 ))
指针参数的函数 暴露类 C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Binary {public : Binary() = default ; Binary(const std ::string & type) : type_(type) {} void set (const std ::string & type) { type_ = type; } void set (const int v) { std ::cout << "overloaded function: " << v << std ::endl ; } const std ::string get () { return type_ + "_mutable" ; } const std ::string get () const { return type_ + "_const" ; } float compute (float a, float b) { std ::cout << "compute " << a << " " << type_ << " " << b << " :" << std ::endl ; if (0 == type_.compare("add" )) return a + b; else if (0 == type_.compare("sub" )) return a - b; else if (0 == type_.compare("mul" )) return a * b; else if (0 == type_.compare("div" )) return a / b; else std ::cout << "unsupport type: " << type_ << std ::endl ; return 0.0f ; } std ::string type_ = "add" ; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include "pybind11/pybind11.h" #include "binary.h" namespace py = pybind11;int sub (int l, int r) { std ::cout << "compute int " << l << " - " << r << " :" << std ::endl ; return l - r; } float sub (float l, float r) { std ::cout << "compute float " << l << " - " << r << " :" << std ::endl ; return l - r; } PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; py::class_<Binary>(m, "Binary" ) .def(py::init<>()) .def(py::init<const std ::string &>()) .def("set" , py::overload_cast<const std ::string &>(&Binary::set ), "set the binary's type." ) .def("set" , py::overload_cast<const int >(&Binary::set ), "test overloaded function." ) .def("get_mutable" , py::overload_cast<>(&Binary::get ), "get the binary's type by mutable." ) .def("get_const" , py::overload_cast<>(&Binary::get , py::const_), "get the binary's type." ) .def("compute" , &Binary::compute, "compute the binary's result." ) .def_readwrite("type_" , &Binary::type_, "the attribute of binary." ) .def("__repr__" , [](const Binary& a) { return "<example.Binary type '" + a.type_ + "'>" ; }); }
注意,py::overload_cast
需 c++14
及其以上版本方可支持。
类函数重载在 c++11
的写法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; py::class_<Binary>(m, "Binary" ) .def(py::init<>()) .def(py::init<const std ::string &>()) .def("set" , (void (Binary::*)(const std ::string &))&Binary::set , "set the binary's type." ) .def("set" , (void (Binary::*)(const int ))&Binary::set , "test overloaded function." ) .def("get" , &Binary::get , "get the binary's type." ) .def("compute" , &Binary::compute, "compute the binary's result." ) .def_readwrite("type_" , &Binary::type_, "the attribute of binary." ) .def("__repr__" , [](const Binary& a) { return "<example.Binary type '" + a.type_ + "'>" ; }); }
Python测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 b1 = CXX.Binary() print(b1) b1.type_ = "div" print(b1.get_mutable()) print(b1.get_const()) b2 = CXX.Binary("sub" ) print(b2.compute(11.0 , 2.0 )) b2.set("mul" ) print(b2.compute(11.0 , 2.0 ))
其他用法 注册模块变量 C++示例源码:
1 2 3 4 5 6 7 8 9 10 11 #include "pybind11/pybind11.h" namespace py = pybind11;PYBIND11_MODULE(compute_pybind_state, m) { m.doc() = "pybind11 compute plugin" ; m.attr("author" ) = "wzx1" ; py::object content = py::cast("HelloWorld" ); m.attr("content" ) = content; }
参考资料