奔头儿

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

前两篇都是介绍Python调用C++的,换句话说,就是需要把C++封装成Python可以“理解”的类型。这篇,我打算说一下,C++怎么去调用Python脚本。其实这两者之间是相通的,就是需要可以互操作。按照惯例,先贴代码。

test.cpp

Cpp代码 收藏代码

  1. <span style="font-size: x-small;">view plaincopy to clipboardprint?  
  2. #include <python2.6/Python.h>  
  3. #include <iostream>  
  4. #include <string>  
  5. void printDict(PyObject* obj) {    
  6. if (!PyDict_Check(obj))    
  7. return;    
  8.     PyObject *k, *keys;    
  9.     keys = PyDict_Keys(obj);    
  10. for (int i = 0; i < PyList_GET_SIZE(keys); i++) {    
  11.         k = PyList_GET_ITEM(keys, i);    
  12. char* c_name = PyString_AsString(k);    
  13.         printf("%s\n", c_name);    
  14.     }    
  15. }    
  16. int main() {    
  17.     Py_Initialize();    
  18. if (!Py_IsInitialized())    
  19. return -1;    
  20.     PyRun_SimpleString("import sys");    
  21.     PyRun_SimpleString("sys.path.append('./')");    
  22. //导入模块  
  23.     PyObject* pModule = PyImport_ImportModule("testpy");    
  24. if (!pModule) {    
  25.         printf("Cant open python file!\n");    
  26. return -1;    
  27.     }    
  28. //模块的字典列表  
  29.     PyObject* pDict = PyModule_GetDict(pModule);    
  30. if (!pDict) {    
  31.         printf("Cant find dictionary.\n");    
  32. return -1;    
  33.     }    
  34. //打印出来看一下  
  35.     printDict(pDict);    
  36. //演示函数调用  
  37.     PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");    
  38.     PyObject_CallFunction(pFunHi, "s", "lhb");    
  39.     Py_DECREF(pFunHi);    
  40. //演示构造一个Python对象,并调用Class的方法  
  41. //获取Second类  
  42.     PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");    
  43. if (!pClassSecond) {    
  44.         printf("Cant find second class.\n");    
  45. return -1;    
  46.     }    
  47. //获取Person类  
  48.     PyObject* pClassPerson = PyDict_GetItemString(pDict, "Person");    
  49. if (!pClassPerson) {    
  50.         printf("Cant find person class.\n");    
  51. return -1;    
  52.     }    
  53. //构造Second的实例  
  54.     PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL);    
  55. if (!pInstanceSecond) {    
  56.         printf("Cant create second instance.\n");    
  57. return -1;    
  58.     }    
  59. //构造Person的实例  
  60.     PyObject* pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);    
  61. if (!pInstancePerson) {    
  62.         printf("Cant find person instance.\n");    
  63. return -1;    
  64.     }    
  65. //把person实例传入second的invoke方法  
  66.     PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);    
  67. //释放  
  68.     Py_DECREF(pInstanceSecond);    
  69.     Py_DECREF(pInstancePerson);    
  70.     Py_DECREF(pClassSecond);    
  71.     Py_DECREF(pClassPerson);    
  72.     Py_DECREF(pModule);    
  73.     Py_Finalize();    
  74. return 0;    
  75. }  </span> 

编译

g++ test.cpp -o test -lpython2.6

testpy.py

Cpp代码 收藏代码

  1. <span style="font-size: x-small;">view plaincopy to clipboardprint?  
  2. #!/usr/bin/python  
  3. # Filename: test.py  
  4. class Person:    
  5.     def sayHi(self):    
  6.         print 'hi'
  7. class Second:    
  8.     def invoke(self,obj):    
  9.         obj.sayHi()    
  10. def sayhi(name):    
  11.     print 'hi',name;  </span> 

执行

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/

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

  1. PyObject* pArgs=PyTuple_New( 1 ); //有几个参数,就是几
  2. 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代码 收藏代码

  1. <span style="font-size: x-small;">#include <boost/python.hpp>  
  2. #include <iostream>
  3. using namespace boost::python;  
  4. class World  
  5. {  
  6. public:  
  7. void set(std::string msg) { this->msg = msg; }  
  8.       std::string greet() { return msg; }  
  9.       std::string msg;  
  10. };  
  11. typedef boost::shared_ptr < World > world_ptr;  
  12. BOOST_PYTHON_MODULE(hello)  
  13. {  
  14.       class_ <World>("World")  
  15.           .def("greet", &World::greet)  
  16.           .def("set", &World::set)  
  17.       ;  
  18.       register_ptr_to_python <world_ptr>();  
  19. }  
  20. int main(int argc, char *argv[])  
  21. {  
  22.     Py_Initialize();  
  23.     world_ptr worldObjectPtr (new World);  
  24.     worldObjectPtr->set("Hello from C++!");  
  25. try
  26.     {          
  27.         inithello();  
  28.         PyRun_SimpleString("import hello");  
  29.         object module(handle <>(borrowed(PyImport_AddModule("__main__"))));  
  30.         object dictionary = module.attr("__dict__");  
  31.         dictionary["pyWorldObjectPtr"] = worldObjectPtr;  
  32.         PyRun_SimpleString("pyWorldObjectPtr.set('Hello from Python!')");  
  33.     }   
  34. catch (error_already_set)   
  35.     {  
  36.         PyErr_Print();  
  37.     }  
  38.     std::cout << "worldObjectPtr->greet(): " << worldObjectPtr->greet() <<std::endl;  
  39.     Py_Finalize();  
  40. return 0;  
  41. }  
  42. </span> 
posted on 2012-08-06 21:03  奔头儿  阅读(3426)  评论(0编辑  收藏  举报