设为首页 收藏本站
查看: 839|回复: 0

[经验分享] c++调用python

[复制链接]

尚未签到

发表于 2015-4-26 05:33:43 | 显示全部楼层 |阅读模式
前两篇都是介绍Python调用C++的,换句话说,就是需要把C++封装成Python可以“理解”的类型。这篇,我打算说一下,C++怎么去调用Python脚本。其实这两者之间是相通的,就是需要可以互操作。按照惯例,先贴代码。
  test.cpp
  Cpp代码 DSC0000.png

  • view plaincopy to clipboardprint?
  • #include
  • #include
  • #include
  • void printDict(PyObject* obj) {
  • if (!PyDict_Check(obj))
  • return;
  •     PyObject *k, *keys;
  •     keys = PyDict_Keys(obj);
  • for (int i = 0; i < PyList_GET_SIZE(keys); i++) {
  •         k = PyList_GET_ITEM(keys, i);
  • char* c_name = PyString_AsString(k);
  •         printf("%s\n", c_name);
  •     }
  • }
  • int main() {
  •     Py_Initialize();
  • if (!Py_IsInitialized())
  • return -1;
  •     PyRun_SimpleString("import sys");
  •     PyRun_SimpleString("sys.path.append('./')");
  • //导入模块
  •     PyObject* pModule = PyImport_ImportModule("testpy");
  • if (!pModule) {
  •         printf("Cant open python file!\n");
  • return -1;
  •     }
  • //模块的字典列表
  •     PyObject* pDict = PyModule_GetDict(pModule);
  • if (!pDict) {
  •         printf("Cant find dictionary.\n");
  • return -1;
  •     }
  • //打印出来看一下
  •     printDict(pDict);
  • //演示函数调用
  •     PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");
  •     PyObject_CallFunction(pFunHi, "s", "lhb");
  •     Py_DECREF(pFunHi);
  • //演示构造一个Python对象,并调用Class的方法
  • //获取Second类
  •     PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");
  • if (!pClassSecond) {
  •         printf("Cant find second class.\n");
  • return -1;
  •     }
  • //获取Person类
  •     PyObject* pClassPerson = PyDict_GetItemString(pDict, "Person");
  • if (!pClassPerson) {
  •         printf("Cant find person class.\n");
  • return -1;
  •     }
  • //构造Second的实例
  •     PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL);
  • if (!pInstanceSecond) {
  •         printf("Cant create second instance.\n");
  • return -1;
  •     }
  • //构造Person的实例
  •     PyObject* pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);
  • if (!pInstancePerson) {
  •         printf("Cant find person instance.\n");
  • return -1;
  •     }
  • //把person实例传入second的invoke方法
  •     PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);
  • //释放
  •     Py_DECREF(pInstanceSecond);
  •     Py_DECREF(pInstancePerson);
  •     Py_DECREF(pClassSecond);
  •     Py_DECREF(pClassPerson);
  •     Py_DECREF(pModule);
  •     Py_Finalize();
  • return 0;
  • }  
  编译
  g++ test.cpp -o test -lpython2.6
  testpy.py
  Cpp代码

  • view plaincopy to clipboardprint?
  • #!/usr/bin/python
  • # Filename: test.py
  • class Person:
  •     def sayHi(self):
  •         print 'hi'
  • class Second:
  •     def invoke(self,obj):
  •         obj.sayHi()
  • def sayhi(name):
  •     print 'hi',name;  
  执行
  lhb@localhost:~/maplib/clib/pyc/invokepy$ ./test
sayhi
__builtins__
__file__
__package__
Person
Second
__name__
__doc__
hi lhb
hi
  我简单解释一下

  • 这个例子演示了,创建python中Person类的实例,并作为参数调用Second的方法。
  • Py_Initialize()和 Py_Finalize()是初始和销毁Python解释器
  • PyRun_SimpleString( "import sys" )导入sys,接着设置py文件的路径PyRun_SimpleString( "sys.path.append('./')" )
  • 导入模块PyImport_ImportModule( "testpy" ),就是testpy.py模块。
  • 获取模块字典列表,PyModule_GetDict(pModule),可以打印出来看一下如 void  printDict(PyObject* obj)函数
  • 从字典中获取类的类型 PyDict_GetItemString(pDict, "Second" ),如函数也是这样获取的
  • 创造类的实例 PyInstance_New(pClassSecond,NULL,NULL)
  • 调用实例的方法PyObject_CallMethod(pInstanceSecond, "invoke" , "O" ,pInstancePerson)
  整个流程就是这样的,并不复杂,如果要进一步研究可以参考:http://www.python.org/doc/

  • Extending and Embedding
  • Python/C API
  比较特殊的是调用Python函数时,参数的传递,就是c++的类型,怎么转换成Python的类型;另外一个问题是,Python函数的返回值,怎么转换成C++中的类型。
C++转换成Python类型,Py_BuildValue()
http://www.python.org/doc/1.5.2p2/ext/buildValue.html

  • PyObject* pArgs=PyTuple_New( 1 ); //有几个参数,就是几
  • PyTuple_SetItem(pArgs, 0 ,Py_BuildValue( "i" , 3 ));  //初始第一个参数,数据类型是i,就是int,值是 3
  返回值转换如,PyArg_ParseTuple,请参考
http://www.python.org/doc/1.5.2p2/ext/parseTuple.html
其实,C++调用Python有两种方式,我前面介绍了第一种方式:通过找到Python模块,类,方法,构造参数来调用。第二中方式,就是通过构造出一个 Python的脚本,用python引擎来执行。第一种方式可能更为优雅,符合大多数的反射调用的特点。(我在以前的一个项目中,实现了c#的反射机制,c#调用Com+,c#调用javascript脚本等)。
  还有一个问题,两种语言互相调用的时候,需要做数据结构(如基本类型,字符串,整数类型等,以及自定义的类等类型)间的转换,共享内存中的一个对象。比如,如何将C++的对象实例传入python中,并在python中使用。c++和python并不在一个进程中,因此可以使用boost的 shared_ptr来实现。
   下面这个例子,主要是演示了,c++调用python,可以在c++中形成一个python脚本,然后利用PyRun_SimpleString调用;并且,构造一个c++的对象,传入到python中,并在python的脚本中调用其函数。
  Cpp代码

  • #include
  • #include
  • using namespace boost::python;
  • class World
  • {
  • public:
  • void set(std::string msg) { this->msg = msg; }
  •       std::string greet() { return msg; }
  •       std::string msg;
  • };
  • typedef boost::shared_ptr < World > world_ptr;
  • BOOST_PYTHON_MODULE(hello)
  • {
  •       class_ ("World")
  •           .def("greet", &World::greet)
  •           .def("set", &World::set)
  •       ;
  •       register_ptr_to_python ();
  • }
  • int main(int argc, char *argv[])
  • {
  •     Py_Initialize();
  •     world_ptr worldObjectPtr (new World);
  •     worldObjectPtr->set("Hello from C++!");
  • try
  •     {
  •         inithello();
  •         PyRun_SimpleString("import hello");
  •         object module(handle (borrowed(PyImport_AddModule("__main__"))));
  •         object dictionary = module.attr("__dict__");
  •         dictionary["pyWorldObjectPtr"] = worldObjectPtr;
  •         PyRun_SimpleString("pyWorldObjectPtr.set('Hello from Python!')");
  •     }
  • catch (error_already_set)
  •     {
  •         PyErr_Print();
  •     }
  •     std::cout

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-60601-1-1.html 上篇帖子: Python入门笔记:学习目录 下篇帖子: python搭建简易服务器
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表