c++调用python
前两篇都是介绍Python调用C++的,换句话说,就是需要把C++封装成Python可以“理解”的类型。这篇,我打算说一下,C++怎么去调用Python脚本。其实这两者之间是相通的,就是需要可以互操作。按照惯例,先贴代码。test.cpp
Cpp代码
[*]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),可以打印出来看一下如 voidprintDict(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]