rss· 投稿· 设为首页· 加入收藏· 繁體版
当前位置: 火魔网 » 程序开发 » Python

Python与C集成

Python与C集成

Author: Vince

近期为了研究一个新的测试工具,需要Python与C集成交互,为此特对Python进行初步的研究和查阅相关资料,得出一个初步的研究成果,供大家分享交流。

一、        软件安装

1、 Python-2.3.3.exe(注意:版本有关系,有些高版本有问题)

2、 VC 6.0

二、        运行环境配置

1、本文默认Python的安装目录为:C:\Python23;在VC IDE中Tools->Options->Directories配置Include files为:C:\Python23\include;Library files为:C:\Python23\libs;

2、如需要Debug版本的要下载python23_d.lib和python23_d.dll这两个文件,也可以下载Python源码来编译获得,具体可查阅相应文档。

三、        C调用Python

1、Test.c源码

int main(int argc, char** argv)

    //初始化Python

    //在使用Python系统前,必须使用Py_Initialize对其

    //进行初始化。它会载入Python的内建模块并添加系统路

    //径到模块搜索路径中。这个函数没有返回值,检查系统

    //是否初始化成功需要使用Py_IsInitialized。

       PyObject *pName,*pModule,*pDict,*pFunc,*pArgs;

    Py_Initialize();

    // 检查初始化是否成功

    if ( !Py_IsInitialized() )

    {

        return -1;

    }

    //添加当前路径

    //把输入的字符串作为Python代码直接运行,返回0

    //表示成功,-1表示有错。大多时候错误都是因为字符串

    //中有语法错误。

       PyRun_SimpleString("import sys");

    PyRun_SimpleString("sys.path.append('./')");

    // 载入名为pytest的脚本

    pName = PyString_FromString("pytest");

    pModule = PyImport_Import(pName);

    if ( !pModule )

    {

        printf("can't find pytest.py");

        getchar();

        return -1;

    }

    pDict = PyModule_GetDict(pModule);

    if ( !pDict )

    {

        return -1;

    }

    // 找出函数名为add的函数

    pFunc = PyDict_GetItemString(pDict, "add");

    if ( !pFunc || !PyCallable_Check(pFunc) )

    {

        printf("can't find function [add]");

        getchar();

        return -1;

    }

    // 参数进栈

    *pArgs;

    pArgs = PyTuple_New(2);

    // PyObject* Py_BuildValue(char *format, ...)

    // 把C++的变量转换成一个Python对象。当需要从

    // C++传递变量到Python时,就会使用这个函数。此函数

    // 有点类似C的printf,但格式不同。常用的格式有

    // s 表示字符串,

    // i 表示整型变量,

    // f 表示浮点数,

    // O 表示一个Python对象。

    PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",3));

    PyTuple_SetItem(pArgs, 1, Py_BuildValue("l",4));

    // 调用Python函数

    PyObject_CallObject(pFunc, pArgs);

    //下面这段是查找函数foo 并执行foo

    pFunc = PyDict_GetItemString(pDict, "foo");

    if ( !pFunc || !PyCallable_Check(pFunc) )

    {

        printf("can't find function [foo]");

        getchar();

        return -1;

    }

    pArgs = PyTuple_New(1);

    PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",2)); //

    PyObject_CallObject(pFunc, pArgs);

    Py_DECREF(pName);

    Py_DECREF(pArgs);

    Py_DECREF(pModule);

    // 关闭Python

    Py_Finalize();

    return 0;

2、 pytest.py源码

def add(a,b):

    print "in python function add"

    print "a = " + str(a)

    print "b = " + str(b)

    print "ret = " + str(a+b)

return

3、运行设置

将pytest.py文件与C工程编译的exe文件存放同一目录下(具体的存放路径应该可以统一配置,在此不便描述),启动编译的exe文件后即可调用pytest.py文件的函数及执行结果。

四、        Python调用C

1、 建立一个目录,整个目录名中不要包含中文。在目录下建立 add.c,内容如下:

#include <Python.h>;

static PyObject* add(PyObject *self, PyObject *args);
//一定声明为static,把他们限制在这个文件范围里。 几乎所有的参数都是PyObject类型。 在python,每个东西都是object。
static PyObject* add(PyObject* self, PyObject* args)    int x=0 ;
   int y=0;
   int z=0;

if (! PyArg_ParseTuple(args, "i|i", &x, &y))

return NULL;
       /*第一个参数是self,这个是python用的, 每个函数都要有。我们暂时不管。args是一个参数列表。她把所有的参数都整合成一个string。所以 我们需要从这个string里来解析我们的参数。PyArg_ParseTuple来完成这个任务。第一个参数是args, 就是我们要转换的参数。第二个是格式符号。“s”代表是个string。 从args里提取一个参数就写"s", 两个的话就写"s|s", 如果是一个string,一个int,就写"s|i", 和printf差不多。第三个     参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add, 他将提取两个参数。分别是x和y。*/
z=x+y;
return Py_BuildValue("i", z);
    /*调用完之后我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把他转换成PyObject, 让python认识。这个用Py_BuildValue 来完成。他是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样, 是个格式化符号。第三个参数 是我们需要转换的参数。Py_BuildValue会把所有的返回只组装成一个tutple给python。*/ static PyMethodDef addMethods[] =
{

   {"add", add, METH_VARARGS, "Execute a shell command."},
   {NULL, NULL, 0, NULL}
};

/*这个是一个c的结构。他来完成一个映射。 我们需要把我们扩展的函数都映射到这个表里。表的第一个字段是python真正认识的。是python 里的方法名字。 第二个字段是python里的这个方法名字的具体实现的函数名。 在python里调用add, 真正执行的是用c写的add函数。第三个字段是METH_VARARGS, 他告诉python,add是调用c函数来实现的。第四个字段是这个函数的说明。如果你在python里来help这个函数,将显示这个说明。相当于在python里的函数的文档说明。*/
PyMODINIT_FUNC initadd()        Py_InitModule("add", addMethods); /*注意,这个函数的名字不能改动。 必须是init+模块名字。 我们的模块名字是add。所以这个函数是initadd()。这样python在导入add 的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。 他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的module的.*/

然后建立setup.py这个文件,内容如下:

#! /usr/bin/python
from distutils.core import setup, Extension
module1 = Extension('add', sources = ['add.c'])
setup (name = 'PackageName', version = '1.0', description = 'This is a demo package', ext_modules = [module1])
在msdos下进入这个目录,输入命令setup.py build。 如果你能编译成功,到你所在目录的build\lib.win32-2.3下会发现add.pyd文件,将文件复制到你所需要的地方(与python同目录下,放在其他目录的话要配置环境变量),启动python,然后:
D:\c>;python
Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>;>;>; import add
>;>;>; print dir(add)
['__doc__', '__file__', '__name__', 'add']
>;>;>; add.add(1,2)
3
>;>;>;

2、 C源码

static PyObject* add(PyObject *self, PyObject *args)

       int x=0 ;

    int y=0;

    int z=0;

    if (!PyArg_ParseTuple(args, "i|i", &x, &y))return NULL;

       z=x+y;

    return Py_BuildValue("i", z);

static PyMethodDef addMethods[] =

   {"add", add, METH_VARARGS, "Execute a shell command,Create by Vince."},

   {NULL, NULL, 0, NULL}

};

PyMODINIT_FUNC initvince()

   Py_InitModule("vince", addMethods);

3、 setup.py

#! /usr/bin/python

from distutils.core import setup, Extension

module1 = Extension('vince', sources = ['Test.c'])

setup (name = 'PackageName', version = '1.0', description = 'This is a demo package', ext_modules = [module1])
setup (name = 'PackageName', version = '1.0', description = 'This is a demo package', ext_modules = [module1])

顶一下
(0)
踩一下
(0)