步骤1:安装Python开发包
由于需要访问Python/C API,首先安装Python开发包.
在Debian,Ubuntu或Linux Mint中:
在CentOS,Fedora或RHEL中:
C中嵌入Python的第一步是初始化Python解释器,这可以用以下C函数完成.
初始化解释器后,需要设置你的C程序中要导入的Python模块的路径.例如,比如你的Python模块位于/usr/local/modules.然后使用以下C函数调用来设置路径.
C中嵌入Python最重要的方面之一是数据转换.从C中传递数据到Python函数,需要首先将数据从C数据类型转换到Python数据类型.Python/C API提供各种函数来实现这.例如,转换C字符串到Python字符串,使用PyString_FromString函数.
另外一个类似函数PyInt_FromLong,将C中long数据类型转换为Python int.每个Python/C API函数返回一个PyObject类型的引用.
当你想嵌入Python代码到另一种语言如C,该代码需要被写成Python模块,然后用另一种语言"导入".所以让我们来看看如何在C中导入Python模块.
为了进行说明,我们实现一个简单的Python模块例子如下:
以上的Python函数有一个字符串作为参数并返回两个重复的字符串.例如,如果输入字符串是"cyberpersons",该函数返回'cyberpersonscyberpersons'.此模块文件命名为"printData.py"并将它放在前面声明的Python模块目录中(/usr/local/modules).
现在你已经定义了Python模块,是时候在C程序中加载它了.导入模块的C代码看起来像这样:
当加载一个模块时,可以调用模块中定义的Python函数.通常,我们需要传递一个或多个参数到一个Python函数.我们必须构建一个Python元组对象,它包括Python函数中的参数.
在我们的例子中,printData函数定义带一个参数的模块.所以呢,我们构建一个大小是一的Python元组对象如下.我们可以使用PyTuple_SetItem设置元组对象的每个项.
我们已经成功构建一个参数传递到函数调用,是时候从C程序调用python函数了.
一旦成功创建Python元组对象作为函数参数,我们可以调用一个带参数的Python函数.为此,通过使用PyObject_GetAttrString首先获得模块中定义的函数的引用,然后使用PyObject_CallObject调用该函数.例如:
避免运行时错误的常见方法是检查函数的返回值并根据返回值采取适当的行动.类似于C程序中的全局变量errno,Python/C API提供一个全局指示符,它报告最后发生的错误.当Python/C API函数失败,全局指示符设置为指示错误,并且PyErr_Print可以用于显示相应的人类可读的trackback.例如:
在你的应用程序中,你可以轻松地将各种错误检查.
这里是完整的C程序,它如本教程描述的嵌入Python代码.
下面是一个例子:
首先是python的一个简单函数
class Hello:
def __init__(self, x):
self.a = x
def print(self, x=None):
print(x)
def xprint():
print("hello world")
if __name__ == "__main__":
xprint()
h.print()1
下面是C语言
#include stdio.h
#include stdlib.h
#include string.h
int main()
{
Py_Initialize();
// 将当前目录加入sys.path
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 导入hello.py模块
PyObject *pmodule = PyImport_ImportModule("hello");
// 获得函数xprint对象,并调用,输出"hello world\n"
PyObject *pfunc = PyObject_GetAttrString(pmodule, "xprint");
PyObject_CallFunction(pfunc, NULL);
PyObject *pclass = PyObject_GetAttrString(pmodule, "Hello");
PyObject *pinstance = PyObject_Call(pclass, arg, NULL);
Py_Finalize();
return 0;
}
编译命令如下:
在C/C++中嵌入Python也比较简单,首先需要在VC中添加Python的include文件目录和lib文件目录:
代码如下:
#include python.h
PyRun_SimpleString("Print 'hi, python!'");
Py_Initialize函数原型是:void Py_Initialize(),在嵌入Python脚本时必须使用该函数,它初始化Python解释器,在使用其他的Python/C API之前必须先调用该函数.可以使用Py_IsInitialized函数判断是否初始化成功,成功返回True.
PyRun_SimpleString函数原型是int PyRun_SimpleString(const char *command),用来执行一段Python代码.注意:是否需要维持语句间的缩进呢?
Py_Finalize函数原型是void Py_Finalize(),用于关闭Python解释器,释放解释器所占用的资源.
PyRun_SimpleFile函数可以用来运行".py"脚本文件,函数原型如下:
int PyRun_SimpleFile(FILE *fp, const char *filename);
PyRun_SimpleString("execfile('file.py')"); //使用execfile来运行python文件
Py_BuildValue()用于对数字和字符串进行转换处理,变成Python中相应的数据类型(在C语言中,所有Python类型都被声明为PyObject类型),函数原型如下:
PyObject *Py_BuildValue(const char *format, .....);
PyString_String()用于将PyObject*类型的变量转换成C语言可以处理的char*型,具体原型如下:
char* PyString_String(PyObject *p);
列表操作函数:
PyObject * PyList_New(Py_ssize_t len);
int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *item);
PyObject * PyList_GetItem(PyObject *list, Py_ssize_t index);
int PyList_Append(PyObject *list, PyObject *item);
int PyList_Sort(PyObject *list);
int PyList_Reverse(PyObject *list);
Py_ssize_t PyList_Size(PyObject *list);
元组操作函数:
int PyTuple_New(Py_ssize_t len);
int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o);
PyObject * PyTuple_GetItem(PyObject *p, Py_ssize_t pos);
int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize); //注意是**指针
字典操作函数:
PyObject * PyDict_New();
int PyDict_SetItem(PyObject *p, PyObject *key, PyObject *val);
int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val);
PyObject* PyDict_GetItem(PyObject *p, PyObject *key);
PyObject* PyDict_GetItemString(PyObject *p, const char *key);
//与PyDict_SetItemString对应
int PyDict_DelItem(PyObject *p, PyObject *key);
int PyDict_DelItemString(PyObject *p, char *key);
int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue);
PyObject* PyDict_Items(PyObject *p);
PyObject* PyDict_keys(PyObject *p);
PyObject* PyDict_Values(PyObject *p);
在C/C++中使用Python对象应正确地处理引用计数问题,否则容易导致内存泄漏.当使用Python/C API中的函数创建列表、元组、字典等后,在对其完成操作后应该使用Py_CLEAR()和Py_DECREF()等宏来销毁这些对象.原型如下:
void Py_CLEAR(PyObject *o);
void Py_DECREF(PyObject *o);
其中,对于Py_CLEAR函数,参数可以为NULL指针,表示不进行任何操作,但是Py_DECREF函数不能为NULL指针,否则导致错误.
使用PyImport_Import()函数可以在C中导入Python模块,返回一个模块对象.函数原型为:
PyObject* PyImport_Import(PyObject *name);
PyModule_GetDict()函数可以获得Python模块中的函数列表,返回一个字典,字典中的关键字为函数名,值为函数的调用地址.原型如下:
PyObject* PyModule_GetDict(PyObject *module);
使用PyObject_CallObject()函数和PyObject_CallFunction()函数可以在C中调用Python中的函数,原型如下:
PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *args);
//args是元组形式
PyObject* PyObject_CallFunction(PyObject *callable, char *format, ......);
//format是类似"iss"这样的参数类型,后面是指定参数
可以使用PyCallable_Check(func)来判断是否可以调用函数,可以则返回True.