Python嵌入C++(2)
在C++中调用python模块。
要在C++中调用python模块,事实上比较复杂,总结如下:
(1)导入要调用函数所在的模块。
(2)在相应的模块中获取要调用的对象。
(3)调用相应的函数。
对于第三步,根据模块中的函数是无参数还是有参数,又可分别对待。对于无参数的函数,上面的三步即可满足要求,但对于有参数的函数,还得扩展上面的第三步,总结如下:
(1)导入要调用函数所在的模块。
(2)在相应的模块中获取要调用的对象。
(3)把要作为参数提供给Python模块的所有C++变量建立参数对象。
(4)调用相应的函数,并为之提供相应的参数。
(5)如果函数有返回值,把返回的值转换为C++变量。
对上面的无参数函数模块的调用示例如下:
(以下示例均在VS.NET 2003及Dev-C++4.9.9.0下面调试通过.)
#include "python.h"
int main(int argc,char** argv)
{
Py_Initialize();
PyObject *myMod = NULL,
*myFunc = NULL;
myMod = PyImport_ImportModule("PythonInC"); //First step.
myFunc = PyObject_GetAttrString(myMod,"Hello");//Second step.
PyEval_CallObject(myFunc,NULL); //Third step.
Py_Finalize();
return (1);
}
其中的模块定义如下:
#Test for mudule nest in C++.
def Hello():
print "Hello,world"
下面给出上面示例中用到的函数原型。
PyObject* PyImport ImportModule(char *name)
Return value: New reference.
This is a simplified interface to PyImport ImportModuleEx() below, leaving the globals and locals
arguments set to NULL. When the name argument contains a dot (when it specifies a submodule of a
package), the fromlist argument is set to the list ['*'] so that the return value is the named module
rather than the top-level package containing it as would otherwise be the case. (Unfortunately,
this has an additional side effect when name in fact specifies a subpackage instead of a submodule:
the submodules specified in the package's all variable are loaded.) Return a new reference
to the imported module, or NULL with an exception set on failure (the module may still be created
in this case | examine sys.modules to find out).
PyObject* PyObject GetAttrString(PyObject *o, char *attr name)
Return value: New reference.
Retrieve an attribute named attr name from object o. Returns the attribute value on success, or
NULL on failure. This is the equivalent of the Python expression `o.attr name'.
下面再来个无返回值单参数的示例:
#include "python.h"
#include <cassert>
int main(int argc,char** argv)
{
Py_Initialize();
PyObject *myMod = NULL,
*myFunc = NULL,
*myArg = NULL;
myMod = PyImport_ImportModule("PythonInC_1"); //First step.
#ifndef NDEBUG
#define NDEBUG
assert(PyObject_HasAttrString(myMod,"Hello");
#undef NDEBUG
#endif
myFunc = PyObject_GetAttrString(myMod,"Hello");//Second step.
myArg = Py_BuildValue("(s)","Bluejugar"); //Third step.
PyEval_CallObject(myFunc,myArg); //Fourth step.
Py_Finalize();
return (1);
}
模块定义为:
PythonInC_1.py:
#Test for single argument function calling.
def Hello(who):
print 'Hello,',who,'!'
新增加函数的原型:
PyObject* Py BuildValue(char *format, ...)
Return value: New reference.
Create a new value based on a format string similar to those accepted by the PyArg Parse*()
family of functions and a sequence of values. Returns the value or NULL in the case of an error;
an exception will be raised if NULL is returned.
有返回值单参数的示例:
#include "python.h"
#include <cassert>
#include <iostream>
int main(int argc,char** argv)
{
Py_Initialize();
PyObject *myMod = NULL,
*myFunc = NULL,
*myArg = NULL,
*myRet = NULL;
myMod = PyImport_ImportModule("PythonInC_2");
#ifndef NDEBUG
#define NDEBUG
assert(PyObject_HasAttrString(myMod,"Hello");
#undef NDEBUG
#endif
myFunc = PyObject_GetAttrString(myMod,"Hello");
myArg = Py_BuildValue("(s)","Bluejugar");
myRet = PyEval_CallObject(myFunc,myArg);
char* sRet = NULL;
PyArg_Parse(myRet,"s",&sRet);
std::cout<<sRet<<std::endl;
Py_Finalize();
return (1);
}
其中的模块重新定义为:
PythonInC_2.py:
#Test for single argument and return value.
def Hello(who):
word = "Hello, " + who + "."
return word
对于模块中的多参数函数,对其传入多个参数时,是传入将每个参数定义成一个对象传入,还是将它们各自定义成一个对象传入?我现在也不是很清楚该怎么做,有些例子上是使用了tuple.
示例如下:
#include "python.h"
#include <cassert>
#include <iostream>
int main(int argc,char** argv)
{
Py_Initialize();
PyObject *myMod = NULL,
*myFunc = NULL,
*myArgs = NULL,
*myRet = NULL;
myMod = PyImport_ImportModule("PythonInC_3");
#ifndef NDEBUG
#define NDEBUG
assert(PyObject_HasAttrString(myMod,"Add");
#undef NDEBUG
#endif
myFunc = PyObject_GetAttrString(myMod,"Add");
myArgs = PyTuple_New(2);
PyTuple_SetItem(myArgs,0,Py_BuildValue("i",2000) );
PyTuple_SetItem(myArgs,1,Py_BuildValue("i",8) );
myRet = PyEval_CallObject(myFunc,myArgs);
int nRet = 0;
PyArg_Parse(myRet,"i",&nRet);
std::cout<<nRet<<std::endl;
Py_Finalize();
return (1);
}
模块定义:
PythonInC_3.py:
#Test for multi-arguments.
def Add(nA,nB):
return (nA + nB)
突然发现动态语言(如Python)竟然先天支持GP(generic programming),很是感触。
附注:虽然开始说是像记日记一样把每日所得记下来,但后来发现如果真是这样,那还是只能写下一些行云流水般的东西,每隔几天,总结一下,再写下来,才算是有所悟,有所得啊.不过这篇文章本来早就写了,不料csdn的blog这几天老是出"运行时错误",听说用的是伪软的ASP.net.哎,看来,伪软的东西也是怎的不怎的啊.("怎"字拼成"za",念三声,"的"字拼成"di",念四声.)