这不是我最早使用swig了,之前在写Kynetix的时候就使用了swig为python封装了C语言写的扩展模块。但是当时我对C++还不是很了解,对其中的一些概念也只是拿来直接用,没有理解到底是什么,为什么会有这种功能。所以昨天我又拿出了《python科学计算》这本书来温习了一下swig那一部分,果然对swig又有了新的认识。

对swig真正全的使用都在swig的文档中有详细的介绍,而且由于swig支持很多种语言,例如java、python、Tcl等,因此这份文档内容相当的丰富。由于现在还没有很好的中文资源,所以现在只能默默的看英文文档了。

SWIG用来做什么?

swig是个封装器,它读取C/C++的函数或者类声明,并将这些函数或者类进行封装,生成一个封装代码,其中包含一个目标语言的文件供目标文件调用,还包含一个C/C++的封装文件以<source>_wrap.c或者<source>_wrap.cxx命名。这个生成的_wrap.cxx文件就是个封装文件,然后我们将这个封装文件同我们自己的C/C++代码或者是已经编译好的目标文件(*.o或者*.obj文件)或者库文件(*.lib/*.a文件)一起编译并连接,就会生成一个我们目标语言能够认识并且调用的模块。

其中的swig生成的封装代码的作用就是能够使得python与C/C++之间能够无阻碍的沟通,也就是

  • 将封装函数接收到的Python对象转换成C/C++能够处理的数据
  • 有了数据以后便执行C/C++的函数
  • 执行C/C++函数将返回值在转换成python对象返回给python代码去处理

简单的操作

swig需要一个*.i文件,也就是swig接口文件(interface)告诉swig需要如何处理C/C++的数据、函数和类。

  1. 先生成封装代码

    1
    $ swig -c++ -python demo.i

    这个命令就会生成python的封装代码,当前路径下会出现demo.pydemo_wrap.cxx文件。其中demo.py文件中是python代码,也就是一个壳子,他能够让python程序调用这个模块中的函数,但是函数的实体并不在里面,因为函数的实体是C/C++编译后的动态库文件。

  2. 编译封装代码
    这一步只说明生成的C/C++的封装代码是可以单独编译的,这就将封装同C/C++库分割开,我按照我的方式写C/C++代码不用管封装的事情,最后只要把wrap的目标文件链接起来就好了。

    1
    $ g++ -fPIC -c demo_wrap.cxx

    需要注意的是-fPIC这个参数是一定要加的,不然就无法生成动态链接库。具体这个参数是做什么的,顾名思义就是生成一个位置独立的代码段,这样无论函数在哪都能够动态的调用这个动态库了,详见:http://stackoverflow.com/questions/5311515/gcc-fpic-option

  3. 链接成扩展模块
    将封装文件与库文件链接成为python能够调用的动态库,这一步就好像是使用wrap这个文件给C/C++库文件进行化妆,化成python认识的那种样子。当然swig也可以根据使用者的需求把C/C++的库化妆成其他语言认识的样子如java、ruby等。
    这样就会生成一个_demo.so或者_demo.pyd的库文件,python可以通过之前的demo.py或者直接_demo.pyd来用自己的方式调用C/C++的函数和类来为自己服务。

    1
    $ g++ -shared demo_wrap.o demo.c -o _demo.so

关于类型映射

.i文件描述了如何创建封装文件,具体的语法我不在这里总结了可以直接去看文档。其中比较重要的部分就是如何让python和C/C++进行交流,比如如何处理python没有指针操作与C/C++传入指针的矛盾,如何处理python返回多个值与C/C++只能返回一个值的矛盾等。

类型映射就是一套规则,告诉swig如何将这些矛盾化解,并定义名称参数,将名称参数写道接口文件的类和函数声明中,让swig处理。
SWIG已经有了默认的一些类型映射,例如* OUTPUT* INPUT* INOUT等来告诉swig这些参数处理成python接口时候怎么处理。
例如如果我在接口文件中声明了一个C函数

1
void add_multi(double x, double y, double * OUTPUT, double * OUTPUT);

这时候swig就认出了OUTPUT是一种类型映射定义的名称参数,C语言修改这两个指针指向的值要处理成python调用这个函数返回这两个指针指向的值的list。

除了使用已定义的类型映射,swig还支持自定义的类型映射,这里我也不多讲了,以后如果在写类型映射的时候我会更新。

回调Python函数

这里主要是能够让C/C++代码调用python的函数。现在必须要理解这一点,因为KMCLib中就用到了这个,使得能够让用户使用python自定义RateCalculator然后重新定义C++的虚函数,是C++程序能够调用python类的方法。
我在这里举一个例子,就是在python中能够继承C++中定义的类,并且在python中重新定义C++类的虚函数。

  1. 开启此功能,在接口文件中的模块名称定义中要加入director参数

    1
    %module(director="1") demo
  2. 在希望能够调用python函数的C++类中,通过%feature指令开启director功能:

    1
    %feature("director") Sum;

我下面把别人的例子贴上来,方便以后自己回忆:

定义一个求和类:

1
2
3
4
5
6
7
8
9
10
11
class Sum
{
public:
Sum() {};
 
~Sum() {};
 
double Cal(int start, int end); // 从start开始到end结束,将Func作用于中间的整数然后球和。
 
virtual double Func(double x) { return x }; // python 中的Sum类的子类可以重写这个虚函数
}

在接口文件中我们放入此类的声明的时候开启”director”功能:

1
2
3
4
5
6
7
8
9
10
11
%feature("director") Sum
{
public:
Sum() {};
 
~Sum() {};
 
double Cal(int start, int end);
 
virtual double Func(double x) { return x };
}

这样在python中我们就可以这么用了:

1
2
3
4
5
import demo
 
class SumReciprocal(demo.Sum): # Sum类的派生类
def Func(self, x): # 重写Sum的Func虚方法
return 1/x

然后我们就可以直接在python中使用这个重写过Sum类方法的子类了。

总结

swig很强大,能够熟练使用,是快速而且方便独立的构建python语言以及其他动态语言的扩展模块,真是感觉我站在了巨人的肩膀上了。

http://pytlab.org/2016/04/02/%E5%88%9D%E8%AF%86%E4%BB%A3%E7%A0%81%E5%B0%81%E8%A3%85%E5%B7%A5%E5%85%B7SWIG/

初识代码封装工具SWIG(回调Python函数)的更多相关文章

  1. Python 3.X 调用多线程C模块,并在C模块中回调python函数的示例

    由于最近在做一个C++面向Python的API封装项目,因此需要用到C扩展Python的相关知识.在此进行简要的总结. 此篇示例分为三部分.第一部分展示了如何用C在Windows中进行多线程编程:第二 ...

  2. Python代码统计工具

    目录 Python代码统计工具 声明 一. 问题提出 二. 代码实现 三. 效果验证 Python代码统计工具 标签: Python 代码统计 声明 本文将对<Python实现C代码统计工具(一 ...

  3. JAVA之旅(五)——this,static,关键字,main函数,封装工具类,生成javadoc说明书,静态代码块

    JAVA之旅(五)--this,static,关键字,main函数,封装工具类,生成javadoc说明书,静态代码块 周末收获颇多,继续学习 一.this关键字 用于区分局部变量和成员变量同名的情况 ...

  4. python中实现延时回调普通函数示例代码

    python中实现延时回调普通函数示例代码 这篇文章主要给大家介绍了关于python中实现延时回调普通函数的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的 ...

  5. Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数

    Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数 内容大纲 1.函数的初识 2.函数的定义 3.函数的调用 4.函数的返回值 5.函数的参数 1.函数初识 # def ...

  6. python 代码检测工具

    对于我这种习惯了 Java 这种编译型语言,在使用 Python 这种动态语言的时候,发现错误经常只能在执行的时候发现,总感觉有点不放心. 而且有一些错误由于隐藏的比较深,只有特定逻辑才会触发,往往导 ...

  7. Python实现代码统计工具——终极加速篇

    Python实现代码统计工具--终极加速篇 声明 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对 ...

  8. 【转】利用Boost.Python将C++代码封装为Python模块

    用Boost.Python将C++代码封装为Python模块 一.     基础篇 借助Boost.Python库可以将C/C++代码方便.快捷地移植到python模块当中,实现对python模块的扩 ...

  9. Python静态代码检查工具Flake8

    简介 Flake8 是由Python官方发布的一款辅助检测Python代码是否规范的工具,相对于目前热度比较高的Pylint来说,Flake8检查规则灵活,支持集成额外插件,扩展性强.Flake8是对 ...

随机推荐

  1. ThinkPHP 5.1 基础知识

    ==========================================//模板中的默认标题{$title|default='默认标题'}========================= ...

  2. postgresql 10 分页

    示例: select * from test limit 2 offset 2; limit:指查多少条数据 offset:从下标多少开始查,下标从0开始,不能为负数. offset计算公式: var ...

  3. tableView刷新中的问题

    在开始之前先上一张效果图 相信大家都看到了“店铺优惠”这一栏,在这里假设这一栏就是单独的一个cell,当无店铺优惠的时候不可点击在有店铺优惠的时候会弹出优惠列表,选中并返回时会刷新数据,所以弹出视图采 ...

  4. Windows Builder(图形化界面的利器)For Eclipse 3.7

    工欲善其事,必先利其器——孔子(春秋)<论语·卫灵公> 今天闲逛论坛的时候,发现了Eclipse 的很好的插件,是关于做图形界面的. 如果想做桌面应用软件,交互界面有点复杂的时候,自己手动 ...

  5. 老毛桃winpe优盘启动系统个性修改全攻略

    PE优盘系统也有很多:大白菜.老毛桃.深度.通用PE工具箱.U大师.电脑店……这些PE优盘系统大多都会捆绑软件安装.更改主页等,一不小心,你就中招.虽然有些是可以自己去取消,但是启动画面还是带有各种L ...

  6. OpenGL超级宝典笔记——深度纹理和阴影 【转】

    目录[-] 光源视角 新型的纹理 深度纹理的大小 首先绘制阴影 然后是光照 投影阴影贴图 阴影比较 之前我们介绍过简单的把物体压平到投影平面来制造阴影.但这种阴影方式有其局限性(如投影平面须是平面). ...

  7. php程序调试: xdebug的配置

    怎样在phpeclipse中像调试Java程序一样调试php呢? XDebug的版本号非常多,打开http://xdebug.org/index.php.把站点细致看一下,你会发现有句"If ...

  8. Seinfeld(杭电3351)

    Seinfeld Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  9. 关于小程序navigator没有高的情况

    传统的web开发者进入小程序的时候,可能有几个映射疑问: div  - > view a -> navigator携带参数传值(a标签应该是根据内容来撑高,而navigator就不会根据内 ...

  10. nginx-location rewrite

    location 语法 location 有”定位”的意思, 根据Uri来进行不同的定位. 在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上. 比如, 碰 ...