Pybind11 是一个轻量级的 C++ 库,用于将你的 C++ 代码暴露给 Python 调用(反之也可,但主要还是前者)。Pybind11 借鉴了 Boost::Python 库的设计,但使用了更为简洁的实现方式,使用了大量 C++11 的新特性,更易于使用。
对于Pybind11和Ctype方式都可以使用Python访问C++代码,但区别在于使用 PyBind11,我们可以更轻松地共享许多数据类型,而使用 ctypes 是一种低级的 C 样式解决方案,共享许多数据类型需要相当多的低级解决方法。例如,虽然ctypes不支持复数等基本的东西,但PyBind11使Numpy与Eigen完全互操作,需要最少的代码。
使用pybind11需要注意的是开发者使用哪个版本编译的pybind11,调用者也必须使用这个版本的python才可以调用。
Pybind11使用:
1、先安装pybind11
pip install pybind11
2、克隆pybind11代码
git clone pybind11代码(https://github.com/pybind/pybind11)
3、加入Python头文件
(1)VS2019创建动态库(我这里是写了一个C++动态库专门存放pybind11的接口),在附加包含目录加入pybind11和python头文件(注意:动态库的cpp文件不要删掉,不然编译无法生产lib文件)
(2)附加库目录:
(3)附加依赖项:
(4)属性-配置属性-高级-目标文件扩展名-改为.pyd
(5)加入如下代码(案例):
#include <pybind11/pybind11.h> #include<Python.h> namespace py = pybind11; PYBIND11_MODULE(pybind, m){ m.doc() = "pybind11的案例"; m.def("func", [](){return "这是pybind11的一个方法";}); }
编译成功会生成.pyd和.lib文件,可以在python中调用pybind11的方法或者类。
注意:PYBIND11_MODULE后面的名字和文件名要相同
一些常见用法案例:
当前文件名为pybindTest.h
#pragma once #include <pybind11/pybind11.h> #include<Python.h> namespace py = pybind11; const char* add(int i, int j) { return "helloworld"; } PYBIND11_MODULE(pybindTest, m){ //可选,说明这个模块是做什么的 m.doc() = "pybind11的案例"; //7/def(“给python调用方法名”,&实际操作的函效, 函数功能说明” ).其中函数功能说明为可选 m.def("add", &add, "A function which adds two numbers", py::arg("i") = 1, py::arg("j") = 2): }
第二条也可以写成m.def(“add”, &add);
python调用:
>>> import sys
>>> sys.path.append(“D:/pybindTest/x64/Debug/”)
>>> import pybindtest
>>> print(pybindtest.add(1,2))
Helloworld
案例2:
py::class_是用来给C++ class 或者 struct-style 的数据结构创建binding的。
py:: init()用来给相应的初始化函数创建binding。
#pragma once #include <iostream> #include <vector> #include <pybind11/pybind11. h> #include <Python.h> #include <pybind11/st1.h> /1 函数中用到了C++的STL库,所以要包含该头文件 namespace py = pybind11; //向量求和,返回一个向量 std::vector<doub1e> sum(const std::vector<doub1e>& vec1, const std::vector<doub1e>& vec2){ auto result = vec1; for(int i = 0:i < vec1.size(); i++){ result[i] += vec2[i]; } return result; } //定义一个向量类 c1ass Vector { public: Vector() = default; ~Vector() = default; std::vector<double> sum(const std::vector<doub1e>& vecl, const std::vector<double>& vec2) { auto result = vec1; for(int i=0;i<vec1.size():i++){ result[i] += vec2[i]; } return result; } } PYBIND11_MODULE(pybindTest, m){ //可选,说明这个模块是做什么的 m.doc() = "pybind11的案例"; //封装函数 m.def(sum,&sum); //封装类 pybindll::class_<Vector> (m "Vector") .def(pybind1::init()) .def("sum", &Vector::sum); }
pybind11封装QT动态库:
Intrument_Controll.h是QT动态库的一个头文件,想要调用这个头文件类中的方法那么需要创建QT动态库,C++动态库不可以调用QT动态库,用pybind11封装好后,在Python命令行下创建对象报错:
在目录下面明明有pybindtest2.pyd文件为啥调用不了?很可能是缺少某些DLL。现在在项目-属性-高级-目标文件扩展名把.pyd改回.dll,编译生成dll后用depend查看pybindtest2.dll缺少哪些dll,查看后得知缺少QT5CORED.DLL。
进入D:\QT\5.15.2\msvc2019_64\bin目录下把QT5CORED.DLL拷贝到pybindtest2目录下然后能正常调用。
注意:pybind11会自动析构间接的类指针
GetModuleByID(1)返回的是IMonocular指针多态调用Monocular子类方法,在GetCaptureDate之后在重复调用一次发现IMonocular指针已经被自动析构了,这种用指针间接调用方式想要不被自动析构有两个方法:
方法一:
写成直接方式:
ptr = intrument.GetModuleByID(1)
data = ptr.GetCaptureDate()
data = ptr.GetCaptureDate()
方式二:
在绑定的子类后面加std::unique_ptr<Monocular, py::nodelete>这样在间接调用类指针的时候不会被主动析构。
python类继承C++中的抽象类:
先在外层写一个中间类继承抽象类,中间类中成员方法的实现格式如下:
案例:MLCameraCallback是一个抽象类
然后在PYBIND11_MODULE(MLColorimeter_py, m)中如下实现:
在python中实现类继承C++抽象类MLCameraCallBack:
📢博客主页: 主页
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 梦回阑珊 原创,首发于 CSDN,转载注明出处🙉
📢代码改变世界,你来改变代码!✨