C/C++项目提供Python接口,有利于融入Python生态。现在Python在应用层有其得天独厚的优势。特别是因为人工智能和大数据,Python现在和未来很长一段时间内都是并将成为最受欢迎的语言之一。那么C/C++是如何提供Python接口的呢?ctypes:C和Python绑定,Python内置模块Boost.Python:C++和Python绑定,Boost模块pybind11:C++11和Python绑定,去掉旧的C++支持,更轻量本文将介绍pybind11环境准备和获取开始了。pybind11:https://github.com/pybind/pyb...环境准备pybind11是一个header-only库,换句话说,你只需要在C++工程中直接包含pybind11的头文件就可以使用了。下面介绍如何在CMake中引入pybind11。更多关于构建系统的介绍,参见官方文档构建系统。获取pybind11,可以gitsubmodule添加子模块,最好固定到某个版本:gitsubmoduleaddhttps://github.com/pybind/pybind11.gitthird_party/pybind11-2.5.0cdthird_party/pybind11-2.5.0/gitcheckouttags/v2.5.0或者,直接获取源码,放到对应的子目录下。在CMakeCMakeLists.txt中添加add_subdirectorypybind11的路径,然后使用提供的pybind11_add_module创建pybind11模块。cmake_minimum_required(VERSION3.1)project(start-pybind11VERSION0.1.0LANGUAGESCCXX)set(MY_PYBIND${MY_CURR}/third_party/pybind11-2.5.0)add_subdirectory(${MY_PYBIND})pybind11_example_pb如果你想扩展pybind11绑定在现有的C++动态库上,然后target_link_libraries可以链接动态库。target_link_libraries(example_pbPUBLICexample)绑定一个函数我们先实现一个add函数,intadd(inti,intj){returni+j;}为了简化工程,可以直接在example_pb.cpp中实现,#include命名空间py=pybind11;intadd(inti,intj){returni+j;}PYBIND11_MODULE(example_pb,m){m.doc()="example_pbbindings";m.def("add",&add,"Afunctionwhichaddstwonumbers");}之后在CMakeLists.txt所在目录执行cmake编译,完成。示例代码first_steps.hfirst_steps.ccfirst_steps_pb.cc绑定了一个类我们先实现一个定时触发类。使用如下:#include#include"tick.h"intmain(intargc,charconst*argv[]){(void)argc;(无效)argv;滴答滴答(500,5000);tick.SetTickEvent([&tick](std::int64_telapsed_ms){std::cout<<"elapsed:"<=2000){tick.停止();}});tick.Start();tick.WaitLifeOver();return0;}运行结果:$./_output/bin/cpp_thread_callback/tick_testelapsed:0mselapsed:500mselapsed:1000mselapsed:1500mselapsed:2000ms该类的声明如下:usingTickEvent=std::function;usingTickRunCallback=std::function;classTick{public:usingclock=std::chrono::high_resolution_clock;Tick(std::int64_ttick_ms,std::int64_tlife_ms=std::numeric_limits::max());Tick(TickEventtick_event,std::int64_ttick_ms,std::int64_tlife_ms=std::numeric_limits::max(),TickRunCallbackrun_beg=nullptr,TickRunCallbackrun_end=nullptr);虚拟~Tick();布尔IsRunning()常量;无效开始();voidStop(boolwait_life_over=false);常量std::chrono::time_point<时钟>&GetTimeStart()常量;voidSetTickEvent(TickEvent&&tick_event);voidSetTickEvent(constTickEvent&tick_event);voidSetRunBegCallback(TickRunCallback&&run_beg);voidSetRunBegCallback(constTickRunCallback&run_beg);voidSetRunEndCallback(TickRunCallback&&run_end);voidSetRunEndCallback(constTickRunCallback&run_end);voidWaitLifeOver();protected://...};然后,pybind11绑定实际如下:#include#include#include#include#包括“cpp/cpp_thread_callback/tick.h”命名空间py=pybind11;使用命名空间pybind11::literals;//NOLINTPYBIND11_MODULE(tick_pb,m){m.doc()="tick_pb绑定";py::class_>(m,"Tick").def(py::init()).def(py::init()).def_property_readonly("is_running",&Tick::IsRunning).def("开始",&Tick::Start).def("停止",&Tick::Stop,"wait_life_over"_a=false).def("get_time_start",&Tick::GetTimeStart).def("set_tick_event",[](Tick&self,constTickEvent&tick_event){self.SetTickEvent(tick_event);}).def("set_run_beg_callback",[](Tick&self,constTickRunCallback&run_beg){self.SetRunBegCallback(run_beg);}).def("set_run_end_callback",[](Tick&self,constTickRunCallback&run_end){self.SetRunEndCallback(run_end);}).def("wait_life_over",&Tick::WaitLifeOver,py::call_guard());}编译出动态库后,把路径添加到PYTHONPATH中:exportPYTHONPATH=:$PYTHONPATH#如果依赖其他动态库,将路径添加到LIBRARY_PATH#linuxexportLD_LIBRARY_PATH=:$LD_LIBRARY_PATH#macOSexportDYLD_LIBRARY_PATH=:$DYLD_LIBRARY_PATH中调用Python:#!/usr/bin/envpython#-*-coding:utf-8-*-#pylint:disable=missing-docstring,import-errorimporttick_pbastickdef_main():t=tick.Tick(lambdaelapsed_ms:print(f"elapsed:{elapsed_ms}ms"),500,1000,lambda:print("运行开始"),lambda:print("运行结束"))t.start()t.wait_life_over()if__name__=="__main__":_main()运行结果:$pythonsrc/pybind/cpp_thread_callback/tick_test.pyrunbegelapsed:0mselapsed:500mselapsed:1000msrunend示例代码tick.htick.cctick_test.ctick_pb.ctick_test.py运行示例code获取代码,gitclonehttps://github.com/ikuokuo/start-pybind11.git#获取子模块cdstart-pybind11/gitsubmoduleupdate--init编译安装,#依赖cmakecdstart-pybind11/安装Comp文件结果,$tree_install_install├──bin│└──cpp_thread_callback│└──tick_test└──lib├──cpp_thread_callback│├──libtick.0.1.0.dylib│├──libtick.0.1.dylib->libtick.0.1.0.dylib│├──libtick.dylib->libtick.0.1.dylib│├──tick_pb.0.1.0.cpython-37m-darwin.so│├──tick_pb.0.1.cpython-37m-darwin.so->tick_pb.0.1.0.cpython-37m-darwin.so│└──tick_pb.cpython-37m-darwin.so->tick_pb.0.1.cpython-37m-darwin.so└──first_steps├──first_steps_pb.0.1.0.cpython-37m-darwin.so├──first_steps_pb.0.1.cpython-37m-darwin.so->first_steps_pb.0.1.0.cpython-37m-darwin.so├──first_steps_pb.cpython-37m-darwin.so->first_steps_pb.0.1.cpython-37m-darwin.so├──libfirst_steps.0.1.0.dylib├──libfirst_steps.0.1.dylib->libfirst_steps.0.1.0.dylib└──libfirst_steps.dylib->libfirst_steps.0.1.dylib5个目录,13个文件添加路径,$sourcesetup.bashfirst_stepscpp_thread_callbackDYLD_LIBRARY_PATH,PYTHONPATH+/Users/John/Workspace/Self/ikuokuo/start-pybind11/_install/lib/first_steps+/Users/John/Workspace/Self/ikuokuo/start-pybind11/_install/lib/cpp_thread_callback运行示例,$pythonsrc/pybind/cpp_thread_callback/tick_test.pyrunbegelapsed:0mselapsed:500mselapsed:1000msrunendEpilogue去编码吧!分享编码方面的实用技巧和知识!欢迎关注,共同成长!