|
Python是一种很好用的胶水语言,利用Python的简洁和C++的高效,基本可以解决99%的问题了,剩下那1%的问题也就不是问题了,毕竟不是所有问题都可解。一般的,Python和C++的交互分为这两种情况:用C++扩展Python:当一个Python项目中出现了性能瓶颈时,将瓶颈部分抽离出来,用C++封装成一个Python可以调用的模块(so库);将Python内嵌入C++:当一个C++项目中有部分功能预期将会经常变更需求,期望获得更高的灵活性时,将这部分功能用Python实现,在C++中进行调用。这里讨论前者,在python中调用C/C++代码的方法很多,这里记录三种方法的使用。1C/C++编译成可执行文件,python通过subprocess调用C/C++代码正常编写,然后编译成exe/elf格式的可执行文件,Python利用subprocess调用该可执行文件即可。好处是改动小,不好是至少需要两个进程跑代码,而且C/C++和Python通讯比较麻烦。这种方法简单粗暴,不太好用,没什么好说的。2ctypesC/C++在编写代码的时候略微改动,然后编译成dll/so格式的动态库文件,Python利用ctypes调用该库文件即可。好处一个进程内运行,C/C++侧改动小,坏处是Python侧需适配代码比较多。ctypes是python自带的一个库,可以用来调用c/cpp的动态链接库。使用ctypes调用c++代码步骤如下:编写cpp代码,将其编译成动态链接库(.so或者.dll文件)。在python代码文件中导入ctypes库,并使用ctypes.cdll.LoadLibrary()方法加载动态链接库。使用ctypes定义c++函数的参数类型和返回值类型,并调用c++函数。2.1编译C++一个简单的demo:dll.cppextern"C"intadd(inta,intb){ returna+b;}123在目录python_call_c_cpp下,使用g++编译dll.cppg++--shared-fPICdll.cpp-olibadd.so1编译完成后,在目录下会生成一个libadd.so文件:2.2python调用C/C++库main.pyimportctypes#加载动态链接库lib=ctypes.cdll.LoadLibrary("./libadd.so")#定义函数参数类型和返回值类型lib.add.argtypes=[ctypes.c_int,ctypes.c_int]lib.add.restype=ctypes.c_int#调用C++函数result=lib.add(1,2)print("调用C++库的结果:"+str(result))1234567891011执行python3main.py:3Boost.PythonBoost作为一个大宝库,提供了我们所需要的这一功能。并且,在Boost的许多库中,已经默认使用了Boost.Python,所以也算是经过了充分的测试。3.1安装Boost的大部分功能都是以头文件的形式提供的,无需安装;但是也有少部分功能,需要进行手动编译。Boost.Python需要进行手动编译。3.2一个简单的demo用C++实现一个模块,在Python中调用时,可以返回一个特定的字符串。#includecharconst*greet(){ return"hello,boost";}BOOST_PYTHON_MODULE(hello_boostpy){ usingnamespaceboost::python; def("greet",greet);}123456789101112将其编译成动态链接库的形式:g++-I/usr/include/python2.7/-fPIC-shared-ohello_boostpy.sohttp://hello_boostpy.cc-lboost_python1这时可以使用ldd看看hello_boostpy.so可不可以找到libboost_python,找不到的话,需要手动将其路径加入环境变量LD_LIBRARY_PATH中,或者用ldconfig相关的命令也可以。在Python中使用hello_boostpy库:#-*-coding:utf-8-*-importsyssys.path.append('.')deftest():importhello_boostpyreturnhello_boostpy.greet()if__name__=="__main__":printtest()123456789101112接下来,我们在C++实现的模块中,添加一个类,并且尝试向C++方向传入Python的list类型对象。C++类:#include#include#include#includeusingnamespaceboost::python;structPerson{ voidset_name(std::stringname){this->name=name;} std::stringprint_info(); voidset_items(list&prices,list&discounts); std::stringname; std::vectoritem_prices; std::vectoritem_discounts;};1234567891011121314151617其中,Python方的list类型,在Boost.Python中有一个对应的实现boost::python::list(相应的,dict、tuple等类型都有对应实现)。在set_items中,我们将会用boost::python::extract对数据类型做一个转换。voidPerson::set_items(list&prices,list&discounts){ for(inti=0;i(prices[i]); doublediscount=extract(discounts[i]); item_prices.push_back(price); item_discounts.push_back(discount); }}12345678910Python模块定义部分依旧是非常直观的代码:BOOST_PYTHON_MODULE(person){ class_
("Person") .def("set_name",&erson::set_name) .def("print_info",&erson::print_info) .def("set_items",&erson::set_items) ; }12345678在Python代码中,就可以像使用一个Python定义的类一样使用Person类了:#-*-coding:utf-8-*-importsyssys.path.append('.')deftest():importpersonp=person.Person()p.set_name('Qie')p.set_items([100,123.456,888.8],[0.3,0.1,0.5])printp.print_info()if__name__=="__main__":test()123456789101112131415
|
|