为了使用C++ 编写python的扩展程序, 需要使用pybind11, pybind11使用比较简单,文档也比较详细。下面本人Windows系统上测试使用pybind11,本篇主要讲述简单样例与原理.平常使用的python实现都是cpython,所以使用C语言或者C++来写一些扩展的时候,就相当于在写cpython的插件。cpython的扩展关键在于要实现一个PyObject* PyInit_modulename(void)的函数,也叫initialization function,这个函数返回一个PyModuleDef 的instance。
开发/测试环境
Ubuntu系统
Ubuntu 18.04pybind11Anaconda3, with python 3.6cmake
Windows系统
win10 64bitMicrosoft Visual Studio 2017Anaconda3, with python 3.7
Pybind11
GitHub - pybind/pybind11: Seamless operability between C++11 and Python
安装配置
下载pybind11或者直接pip install pybind11
git clone https://github.com/pybind/pybind11.git
添加一个c++ add算子
//ex.cpp #includeint add(int i, int j) { return i + j; } PYBIND11_MODULE(ex, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("add", &add, "A function which adds two numbers"); }
编译为so动态链接库,供pythonimport调用
#该编译命令会生成 ex.cpython-35m-x86_64-linux-gnu.so g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` ex.cpp -o gemfield`python3-config --extension-suffix`
python测试
>>> import ex >>> ex.add(1,1) 2
那么看看PYBIND11_MODULE的宏展开之后执行了什么。
可以看到实现了PyObject *PyInit_ex()函数。
static void pybind11_init_ex(pybind11::module &);
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_ex() {
{
const char *compiled_ver ="3.8";
const char *runtime_ver = Py_GetVersion();
size_t len = std::strlen(compiled_ver);
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {
PyErr_Format(PyExc_importError, "Python version mismatch: module was compiled for Python %s, " "but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver);
return nullptr;
}
}
auto m = pybind11::module("ex");
try {
pybind11_init_ex(m);
return m.ptr();
} catch (pybind11::error_already_set &e) {
PyErr_SetString(PyExc_importError, e.what());
return nullptr;
} catch (const std::exception &e) {
PyErr_SetString(PyExc_importError, e.what());
return nullptr;
}
}
void pybind11_init_ex(pybind11::module &m){
m.doc() = "pybind11 example plugin";
m.def("add", &add, "A function which adds two numbers");
}
面向对象编写类
如何对c++类进行python绑定呢
#include#include extern "C" bool initav(const char* url); class EXClass{ public: EXClass(const std::string &url) : url(url){initav(url.c_str());} const std::string &getframe() const; private: std::string url; }; const std::string& EXClass::getframe() const { std::cout<< url << std::endl; return url; } PYBIND11_MODULE(cxvlass, m) { pybind11::class_ (m, "EXClass") .def(pybind11::init ()) .def("getframe", &SYSZUXav::getframe); }
编译
g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` syszuxav.cpp -o syszuxav`python3-config --extension-suffix`
同样展开宏查看,可以看到还是实现了
可以看到实现了PyObject *PyInit_exclass()函数。
extern "C" bool initav(const char* url);
class EXClass{
public:
EXClass(const std::string &url) : url(url){initav(url.c_str());}
const std::string &getframe() const;
private:
std::string url;
};
const std::string& EXClass::getframe() const
{
std::cout<< url << std::endl;
return url;
}
static void pybind11_init_exclass(pybind11::module &);
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_exclass()
{
{
const char *compiled_ver = "3.8";
const char *runtime_ver = Py_GetVersion();
size_t len = std::strlen(compiled_ver);
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {
PyErr_Format(PyExc_importError, "Python version mismatch: module was compiled for Python %s,
but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver);
return nullptr;
}
}
auto m = pybind11::module("exclass");
try {
pybind11_init_exclass(m);
return m.ptr();
} catch (pybind11::error_already_set &e) {
PyErr_SetString(PyExc_importError, e.what());
return nullptr;
} catch (const std::exception &e) {
PyErr_SetString(PyExc_importError, e.what());
return nullptr;
}
}
void pybind11_init_syszuxav(pybind11::module &m)
{
pybind11::class_(m, "SYSZUXav").def(pybind11::init()).def("getframe", &SYSZUXav::getframe);
}
后续将会结合pip setup+opencv详细说明如何构建python package c++



