软件测试交流论坛

 找回密码
 立即注册
查看: 243|回复: 3

Python与C集成

[复制链接]

51

主题

54

帖子

199

积分

超级版主

Rank: 8Rank: 8

积分
199
QQ
发表于 2017-4-29 23:51:33 | 显示全部楼层 |阅读模式

近期为了研究一个新的测试工具,需要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源码

[cpp] view plain copy


  • 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, "vcadd");   
  •     if ( !pFunc || !PyCallable_Check(pFunc) )   
  •     {   
  •         printf("can't find function [vcadd]");   
  •         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, "vcfoo");   
  •     if ( !pFunc || !PyCallable_Check(pFunc) )   
  •     {   
  •         printf("can't find function [vcfoo]");   
  •         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源码

[python] view plain copy


  • 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,内容如下:

[cpp] view plain copy


  • #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("vince", addMethods);   
  • }   
  • /*注意,这个函数的名字不能改动。 必须是init+模块名字。 我们的模块名字是add。所以这个函数是initadd()。这样python在导入add 的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。 他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的module的.*/  


然后建立setup.py这个文件,内容如下:
[python] view plain copy


  • #! /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,然后:

[python] view plain copy


  • 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源码

[cpp] view plain copy


  • 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
[python] view plain copy


  • #! /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_modu



十年前选择软件测试出于工作机会;
坚持十年软件测试出于个人的专长;
现在继续软件测试出于追求和梦想!
回复

使用道具 举报

0

主题

2

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2017-5-2 11:03:03 | 显示全部楼层
好厉害!
回复

使用道具 举报

0

主题

15

帖子

131

积分

注册会员

Rank: 2

积分
131
发表于 2017-5-2 15:23:18 | 显示全部楼层
好像很高端
回复

使用道具 举报

0

主题

1

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2017-5-2 18:17:06 | 显示全部楼层
一脸萌币
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|门道科技  

GMT+8, 2018-5-27 09:36

Powered by 门道科技

© 2010-2020 MTesting Inc.

快速回复 返回顶部 返回列表