虽然python开发效率很高,但作为脚本语言,其性能不高,所以为了兼顾开发效率和性能,通常把性能要求高的模块用c或c++来实现或者在c或c++中运行python脚本来处理逻辑,前者通常是python中一些模块的实现方式,后者服务端程序(实现业务扩展或是Plugin功能)和游戏开发(脚本只处理逻辑)中比较常见。本文主要介绍通过在c中运行python脚本来实现python与c的相互调用,并通过c和python脚本设置同一段内存区域为例子来讲解。
  准备工作
  为了在c中运行python脚本,需要在程序链接的时候将python虚拟机库链接进去,python虚拟机库是python安装目录下libs中的python27.lib文件,至于怎样将库链接进程序中可以自己google下。由于在c中使用了python的一些方法和数据结构,所以需要将python安装目录下的include目录添加到项目include目录中。好了,需要准备的是这些,然后可以开始实现一个设置内存区域的例子了。
  内嵌python虚拟机
  在c中内嵌python虚拟机很简单,只需要在程序开头include Python.h头文件,然后调用下面两段来初始化python虚拟机实例行了。
  1 Py_SetPythonHome("D:Python27");
  2 Py_Initialize();
  Py_SetPythonHome函数是用来设置python的库路径,也是python安装路径,Py_Initialize函数真正实例化一个python虚拟机,这样把一个python虚拟机内嵌到c中了。
  调用python脚本
  将python虚拟机初始化后,其实可以调用python脚本了。c中调用脚本模块中的方法分下面几个步骤:
  1、使用PyImport_ImportModule导入脚步模块;
  2、使用PyObject_GetAttrString获取模块特定方法信息;
  3、使用Py_VaBuildValue转换输入参数;
  4、使用PyObject_CallObject调用特定方法;
  5、使用PyArg_Parse转换方法的返回结果。
  由于上面流程在调用模块中的方法都是必须的,所以可以写个函数来封装上面的5个步骤,具体代码如下:
1 int PyModuleRunFunction(const char *module, const char *function,
2                         const char *result_format, void *result, const char *args_format, ...)
3 {
4
5     PyObject *pmodule, *pfunction, *args, *presult;
6
7     pmodule = PyImport_ImportModule(const_cast<char *>(module));
8     if (!pmodule)
9     {
10         PyObject *type = PyErr_Occurred();
11         if (type == PyExc_NameError)
12         {
13             PyErr_Clear();
14             return 0;
15         }
16
17         PyError("PyModuleRunFunction");
18         return -1;
19     }
20
21     pfunction = PyObject_GetAttrString(pmodule, const_cast<char *>(function));
22     Py_DECREF(pmodule);
23     if (!pfunction)
24     {
25         PyObject *type = PyErr_Occurred();
26         if (type == PyExc_AttributeError)
27         {
28             PyErr_Clear();
29             return 0;
30         }
31
32         PyError("PyModuleRunFunction");
33         return -2;
34     }
35
36     if (pfunction == Py_None)
37     {
38         return 0;
39     }
40
41     va_list args_list;
42     va_start(args_list, args_format);
43     args = Py_VaBuildValue(const_cast<char *>(args_format), args_list);
44     va_end(args_list);
45
46     if (!args)
47     {
48         Py_DECREF(pfunction);
49         return -3;
50     }
51
52     presult = PyObject_CallObject(pfunction, args);
53     if (presult == 0)
54     {
55         PyError("PyModuleRunFunction");
56         Py_XDECREF(pfunction);
57         Py_XDECREF(args);
58         return -1;
59     }
60
61     Py_XDECREF(pfunction);
62     Py_XDECREF(args);
63
64     return ConvertResult(presult, result_format, result);
65 }
  有了上面的调用python模块内方法的通用函数,我们可以直接调用python脚本中的方法了,具体如下:
  1 PyModuleRunFunction("hello", "test", "", 0, "()");
  这样我们实现了再c中调用python的方法。下面我们再来开心python怎么调用c中的方法。