使用swig实现C++的python扩展功能

 1. 直接C扩展Python的方法
  Python的扩展API是主要为C语言提供的,可以利用该API为要导出的C函数建立包装器(wrapper)。包装器用来处理Python对象与底层C函数中的变量所需值之间的转换,并将C函数注册到Python的自定义module中。
  假设将要导出的函数成为模块函数,对应wrapper中的函数为包装函数。则wrapper文件主要包含以下几个部分:
include "Python.h";
每个模块函数的包装函数,即:PyObject* Module_func();
模块函数与包装函数的映射表,即:PyMethodDef ModuleMethods[]对应表;
模块的初始化函数:void initModule()部分。


  简单示例程序:
  假设有以下C文件TestModel.c:

int add(int x,int y)
{

    return x+y;
}
  我们要导出其中的函数add(),则要为之写wrapper。文件内容如下:

include "Python.h";
extern int add(int);
PyObject *add_wrap(PyObject *self, PyObject *args)
{
    int x=0 ;
    int y=0;
    int result=0; 
    if (! PyArg_ParseTuple(args, "i|i", &x, &y))

    return NULL;

    result = add(x,y)

    return Py_BuildValue("i", result);
}

参数说明:

    第一个参数是self,这个是python用的,每个函数都要有。我们暂时不管。  

    第二个参数是args,它是一个参数列表。她把所有的参数都整合成一个string。所以我们需要从这个string里来解析我们的参数。我们使用python内置函数PyArg_ParseTuple来完成这个任务。其中,第一个参数是args,就是我们要转换的参数;第二个是格式符号。“s”代表是个string。从args里提取一个参数就写"s", 两个的话就写"s|s", 如果是一个string,一个int,就写"s|i", 和printf差不多;第三个参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add,他将提取两个参数。分别是x和y。

 

调用完add后,我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把它转换成PyObject,让python认识。这个用Py_BuildValue来完成。它是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样,是个格式化符号。第二个参数是我们需要转换的参数。Py_BuildValue会把所有的返回值组装成一个tutple给python。

static PyMethodDef TestModelMethods[] =

{
  {"add", add_wrap, METH_VARARGS, "add two number to one number"},
  {NULL, NULL, 0, NULL}
};

 

   这个是一个c的结构。它来完成一个映射。我们需要把我们扩展的函数都映射到这个表里。表结构说明如下:

     第一个字段是python真正认识的。是python里的方法名字。

     第二个字段是python里的这个方法名字的具体实现的函数名。在python里调用add,真正执行的是用c写的add_wrap函数。
     第三个字段是METH_VARARGS,他告诉python,add_wrap是调用c函数来实现的。

     第四个字段是这个函数的说明。如果你在python里来help这个函数,将显示这个说明。相当于在python里的函数的文档说明。

void initTestModel(void)
{
    Py_InitModule("TestModel", TestModelMethods);
}

   注意,这个函数的名字不能改动。必须是init+模块名字。我们的模块名字是TestModel。所以这个函数是initTestModel()。

这样python在导入TestModel的模块时候,才会找到initTestModel()这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。

他表示,TestModel这个模块使用TestModelMethods这个映射表。python应该这样导入我们的module的.然后我们可以将生成的模块导入到Python环境中,并调用其中的函数。

 
2. 怎样用SWIG生成C的wraper
  SWIG是一个自动的扩展构造工具。它读入注释的源程序头文件(后缀为.i的脚本文件),为python、tcl、perl等多种脚本语言产生wrap代码。
  步骤大致为:
(1) 写源程序;
(2) 写后缀为.i的脚本文件;
(3) 使用命令"swig -python TestModel.i"生成TestModel_wrap.c,example_wrap.doc;
(4) 编译连接成共享库。
  .i脚本文件的格式很简单,只需要列出要导出的函数或类型,并注释必要信息。还以上面的TestModel.c为例,写TestModel.i脚本文件如下:

%module TestModel
%{
#include "TestModel.h"
%}
extern int add(int);

  在命令行输入以下命令"swig -python TestModel.i",会在当前目录下生成TestModel_wrap.c,TestModel_wrap.doc两个文件。前者即为TestModel.c的wrap文件,后者为解释文件。
  接下来使用编译连接命令生成TestModel.so文件。命令同第一节:
  接下来就可以在Python环境中使用TestModel模块中的函数了。

3. 用SWIG生成C++的wraper
  用SWIG生成C++的wrapper过程类似于C wrapper。它的步骤如下:
(1) 写.cpp源程序;
(2) 写.i脚本文件;
(3) swig -c++ -python foo.i
生成TestModel_wrap.c,TestModel_wrap.doc;
(4) 编译连接成共享库TestModel.so。
则生成Python的foo模块,可以通过调入foo模块使用其中的类成员函数、成员变量。
  一个简单示例:
  假设有如下C++源程序:

class TestModel
{
public:
    TestModel();
    void add(int value);
 };
  对应实现的cpp文件如下:

#include "TestModel.h"

TestModel::TestModel()
{
    printf("测试模块");
}

int TestModel::add(int x,int y)
{

     return x+y;
}

为之写TestModel.i文件:
%module TestModel
%{
#include "TestModel.h"
%}

class TestModel

{
public:
    TestModel();
    int add(int x,int y);
};

编译方式:

(1.控制台方式)
 在控制台里执行使用命令:"swig -c++ -python TestModel.i",得到TestModel_wrap.c,TestModel_wrap.doc(有些系统生成的是number.py)两个文件。  
  生成TestModel.so文件,可以在Python环境中使用TestModel类及其成员函数。但类名和成员函数名稍有变化,具体可见生成的TestModel_wrap.doc(或number.py)文件。

(2.编辑器方式)

在.net编辑器里选中.i文件,然后在属性里进行设置:

命令行:

..\SDK\swigwin\swig  -c++ -python -outdir $(ConfigurationName) -I../.. "$(InputPath)"

输出:$(InputDir)$(InputName)_wrap.cxx

并且在工程属性里要指定python库的相关文件,包括include和libs。

最后,进行编译得到*.cxx文件,然后将该文件添加到工程重新进行编译。


  也可以在C++里执行,如下:

#include <iostream>
#include <string>
#include "TestModel_wrap.cxx"

int main() {

    Py_Initialize();                // initialize python 
    init_Test();  //在test_wrap.cxx里定义的。

    PyRun_SimpleString("import testpy\n

                        a = TestModel.TestModel()\n

                        b =a.add(1,2)\n

                        print b\n");

    Py_Finalize();                  // shut down python
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值