初识代码封装工具SWIG(回调Python函数)
这不是我最早使用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$ swig -c++ -python demo.i这个命令就会生成python的封装代码,当前路径下会出现
demo.py
和demo_wrap.cxx
文件。其中demo.py
文件中是python代码,也就是一个壳子,他能够让python程序调用这个模块中的函数,但是函数的实体并不在里面,因为函数的实体是C/C++编译后的动态库文件。 -
编译封装代码
这一步只说明生成的C/C++的封装代码是可以单独编译的,这就将封装同C/C++库分割开,我按照我的方式写C/C++代码不用管封装的事情,最后只要把wrap的目标文件链接起来就好了。1$ g++ -fPIC -c demo_wrap.cxx需要注意的是
-fPIC
这个参数是一定要加的,不然就无法生成动态链接库。具体这个参数是做什么的,顾名思义就是生成一个位置独立的代码段,这样无论函数在哪都能够动态的调用这个动态库了,详见:http://stackoverflow.com/questions/5311515/gcc-fpic-option -
链接成扩展模块
将封装文件与库文件链接成为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++类的虚函数。
-
开启此功能,在接口文件中的模块名称定义中要加入
director
参数1%module(director="1") demo -
在希望能够调用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/
相关文章
- 【Python成长之路】python 基础篇 -- global/nonlocal关键字使用
- Python程序 #!/usr/bin/python 的解释
- Python 字符串_python 字符串截取_python 字符串替换_python 字符串连接
- [Python] Simple Decorators
- [Python] Optimizing code with numpy intersect1d, and Set
- 【Python实战】python中含有中文字符无法运行
- Python的Asyncore异步Socket模块及实现端口转发的例子
- python 字符串
- python-面向对象-05_面向对象封装案例 II
- Python每日一练(20230310)
- Python 刷Leetcode题库,顺带学英语单词(6)
- Atitit web httphandler的实现 java python node.js c# net php 目录 1.1. Java 过滤器 servelet1 1.2. Python的
- Python:python语言中与时间有关的库函数简介、安装、使用方法(获取当前时间/计算程序块前后运行时间/模型训练时间或耗费时间)之详细攻略
- Python:利用python语言实现18位身份证号码和15位身份证号码相互转换
- Python:pmml格式文件的简介、安装、使用方法(利用python将机器学习模型转为Java常用的pmml格式文件)之详细攻略
- Python之多线程:python多线程设计之同时执行多个函数命令详细攻略
- Python语言学习之文件夹那些事:python和文件夹的使用方法之详细攻略
- Python之Pypi:Pypi的简介、使用方法(如何将自己的Python项目(自定义程序代码库)发布到PyPI全流程的简介)之详细攻略
- python爬虫技术如何挣钱?教你爬虫月入三万!
- python实现--参数估计
- 雅虎财经数据python 网络爬虫stock股票 用 Python 通过雅虎财经获取股票数据
- python IDLE 背景修改 IDLE (Python GUI)
- python爬取知乎评论
- 【计算机二级Python】模拟试卷第2套选择题
- Python 封装WebSocket通信
- Python ---- 算法入门(3)分治算法解决【汉诺塔】问题
- Python Selenium Unittest 自动化测试 简单封装类