请选择 进入手机版 | 继续访问电脑版
楼主: fantuanxiaot
11875 188

[源码分享] [转载]Python笔记:C/C++调用Python和python调用C/C++模块   [推广有奖]

Ψ▄┳一大卫卍卐席尔瓦

大师

8%

还不是VIP/贵宾

-

威望
7
论坛币
-234475 个
通用积分
123.7824
学术水平
3783 点
热心指数
3819 点
信用等级
3454 点
经验
150207 点
帖子
7546
精华
32
在线时间
1327 小时
注册时间
2013-2-3
最后登录
2022-2-24

初级学术勋章 初级热心勋章 中级热心勋章 中级学术勋章 初级信用勋章 中级信用勋章 高级热心勋章 高级学术勋章 特级学术勋章 特级热心勋章 高级信用勋章 特级信用勋章

fantuanxiaot 发表于 2015-2-19 09:44:42 |显示全部楼层 |坛友微信交流群

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

C/C++调用Python


最近因为研究一个东西,并且在很久以前就想把python好好看看。正好满足我的好奇心。我每天上班做得游戏都是用lua,也是一门很强大的脚本语言。可能我更喜欢python的缩进区分和面向对象吧。 今天只写一个简单的例子。一个简单的python脚本,就一个函数,用C/C++去调用。可能这也是作为程序来说最关心的一件事。所以我的python笔记也就最先写这块。- - 好切入正题:

#include <Python.h>
#include <stdio.h>

void test( void )
{
PyObject *pMod = NULL;
PyObject *pFun = NULL;
PyObject *pParm = NULL;
PyObject *pRetVal = NULL;
int iRetval = 0;

if ( pMod = PyImport_ImportModule( "add" ) )
{
if ( pFun = PyObject_GetAttrString( pMod, "add" ) )
{
pParm = PyTuple_New( 2 );
PyTuple_SetItem( pParm, 0, Py_BuildValue( "i", 300 ) );
PyTuple_SetItem( pParm, 1, Py_BuildValue( "i", 500 ) );
pRetVal = PyEval_CallObject( pFun, pParm );
PyArg_Parse( pRetVal, "i", &iRetval );
printf( "result: %d/n", iRetval );
}
else
printf( "Not found fun!/n" );
}
else
printf( "Not found module!/n" );
}

int main( void )
{
Py_Initialize();
if ( !Py_IsInitialized() )
return -1;

try
{
PyRun_SimpleString( "import sys" );
PyRun_SimpleString( "sys.path.append( './' )" );
PyRun_SimpleString( "print sys.path" );
}
catch ( ... )
{
printf( "Error to import!" );
}

test();

Py_Finalize();
return 0;
}

首先,我使用的是python2.6,在测试脚本调用的程序,DEBUG下需要python26_d.dll和python26_d.lib这两个调试版的库。这两个库网上有现成的可以下载,也可以自己编译。当然python的SDK是肯定需要的。这个例子的test函数是我在网上随便COPY的一份,自己只是整理了下。很多COPY的代码,我都喜欢自己整理一下,至少看起来更舒服清晰一点。也可以说规范一点。

主函数里 Py_Initialize();初始化python解释器,之后是判断是否初始化成功。红色的try块可以用来设置自己的python模块搜索路径。PyRun_SimpleString此函数可以很方便的执行一句python脚本语句。

PyRun_SimpleString( "import sys" );这句相当于在python脚本里写:import sys语句,然后执行。

后面的一个道理,我在这里使用sys.path.append将默认搜索路径设置到当前。当然你可以设置成其他的路径,可以是相对路径也可以是绝对路径。之后我做了一个打印。看看这些路径都是些什么。或者你可以直接将你写好的将要用到CC++中来调用的脚本(.py)文件放到其中任意一个path中。在后面的加载模块函数就能够搜索到你写的py文件了。

这里我写的add.py脚本文件很简单,就一个函数:

def add( a, b)

return a + b

python是以缩进来判断是否属于函数体的。我们要在程序中调用这个函数,首先就得加载这个add.py文件。我将这个文件放在了工程目录里。然后test函数里使用PyImport_ImportModule 加载add.py文件。加载成功后,获取函数指针,这个有那点像查找dll中的函数,呵呵!pParm = PyTuple_New( 2 );构建add函数的参数元组。之后就是传入两参数300和500,"i"表示是整数。之后就是调用改脚本函数。返回值最后打印出来,结果就是:800.

好了,这个例子很简单,就当留个足迹,要扩展的很多。一个基本的调用模型完成了。




python调用C/C++模块

前一篇讲了简单的C/C++调用Python脚本模块(.py)。既然是用于诸多游戏程序的脚本语言,那肯定是缺不了互调(礼尚往来)。因此,本篇讲一个简单的python调用C/C++写的DLL模块,对Python进行功能扩展。这里写一个简单的例子,主要就为了了解下这么用Python来调用C/C++写的DLL库。好了,切入正题: 首先,我是用VS2003建的一个DLL工程,将DLL工程属性里面的输出文件的(.dll)改为(.pyd)。当然也可以将生成后的DLL扩展名改为.pyd。呵呵!免得大家以为它很神秘(VC还能生成.pyd库?这种疑问!)好,直接贴代码:#include <Python.h> int cmd( const char *arg )
{
     int n = system( arg );
     return n;
}

static PyObject * wrap_cmd_fun( PyObject *self, PyObject *args )
{
     const char * command;
     if ( !PyArg_ParseTuple( args, "s", &command ) )
          return NULL;
     int n = cmd( command );
     return Py_BuildValue( "i", n );
}

static PyMethodDef MyCppMethods[] =
{
     { "MyCppFunc", wrap_cmd_fun, METH_VARARGS, "Execute a shell command." },
     { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initMyFirstPythonModule( void )
{
     PyObject *m = Py_InitModule( "MyFirstPythonModule", MyCppMethods );
     if (m == NULL)
         return;
}
这个实例很简单,首先是Py_InitModule用于初始化在Python脚本中要import的模块,这里的模块名是:MyFirstPythonModule。我们在Python中将使用import MyFirstPythonModule 来载入这个模块。这里我们将MyCppMethods作为模块要调用的方法,它是一个PyMethodDef结构。我们可以看到这个结构的数组定义,{ "MyCppFunc", wrap_cmd_fun, METH_VARARGS, "Execute a shell command." }, 红色的就是我们在脚本里面要调用的函数名字,它被映射为wrap_cmd_fun,当在Python脚本中调用MyCppFunc时将会调用wrap_cmd_fun函数。第三个METH_VARARGS成员表示调用方式,可以用或运算连接几个调用方式。第四个成员是一个方法的说明,这里说明他是一个用来执行控制台命令的。数组的第二个元素{ NULL, NULL, 0, NULL } 表示函数列表结束,结束就用NULL。言外之意就是我们可以再这个结构数组中映射多个C/C++函数用于python来调用。wrap_cmd_fun函数就不用我来解释了吧,一看就懂,就是将Python调用时传进来的参数转化成字符串,然后调用cmd函数,返回值是整型,又传回给python程序。给出一个格式化时的"i", "s"之类的Python脚本类型说明表:

格式化字符

C数据类型

Python类型

s

char*

字符串

s#

char*, int

字符串及长度

z

char*

与s相同,但可以为NULL
续表

格式化字符

C数据类型

Python类型

z#

char*, int

与s#相同,但可以为NULL

i

int

长整型

l

long int

长整型

c

char

单个字符的字符串

f

float

双精度型

d

double

双精度型
好了,我们开始编译,编译出来的库文件为:MyFirstPythonModule.pyd之后我们写Python脚本:import MyFirstPythonModule                                  #引用库文件。
input = MyFirstPythonModule.MyCppFunc( "dir" )  #调用函数,传入得是dir命令。
print input                                                              #将返回值打印出来。
好了!就这么简单。之所以用CC++模块的形式,是为了提高Python脚本的性能,也是为了交互。更多的好处还得在使用中得以体现。有什么说得不对的地方还望大家批评!


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:python Command Initial include Methods python

回帖推荐

hkmonte 发表于185楼  查看完整内容

高手啊~~~要多多学习了~~~

nietzschetmh 发表于182楼  查看完整内容

鼓励原创 赞一个楼主

bbslover 发表于181楼  查看完整内容

thanks for sharing this

zbin7451f 发表于183楼  查看完整内容

楼主慷慨!新年快乐!
已有 2 人评分经验 学术水平 热心指数 信用等级 收起 理由
zbin7451f + 100 + 5 + 5 + 5 对论坛有贡献
oink-oink + 5 + 5 + 5 精彩帖子

总评分: 经验 + 100  学术水平 + 10  热心指数 + 10  信用等级 + 10   查看全部评分

本帖被以下文库推荐

xilongyao 在职认证  发表于 2015-2-19 09:44:43 |显示全部楼层 |坛友微信交流群
O(∩_∩)O哈哈~,沙发是我的啦
xilongyao 于 2015-2-20 08:29 使用 抢沙发 抢夺本帖沙发
已有 1 人评分论坛币 收起 理由
fantuanxiaot + 8 精彩帖子

总评分: 论坛币 + 8   查看全部评分

使用道具

夏夜炊烟 发表于 2015-2-19 10:20:18 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

新年好

使用道具

eric5488 发表于 2015-2-19 10:23:49 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

很棒的分享, 謝謝

使用道具

eric5488 发表于 2015-2-19 10:25:35 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

謝謝樓主大放送

使用道具

oink-oink 发表于 2015-2-19 10:27:22 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

使用道具

scucook103 发表于 2015-2-19 10:27:52 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

高大上

使用道具

oink-oink 发表于 2015-2-19 10:27:56 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

使用道具

oink-oink 发表于 2015-2-19 10:28:34 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

使用道具

chengli 发表于 2015-2-19 10:28:45 |显示全部楼层 |坛友微信交流群

回帖奖励 +8

楼主慷慨!新年快乐!

使用道具

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

本版微信群
加好友,备注jr
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-3-28 22:42