CWYAlpha

Just another WordPress.com site

Thought this was cool: 写python的c扩展简介

leave a comment »


python是一门非常方便的动态语言,很多你用c或者java要很多行的代码,可能python几行就搞定了,所以python社区一直有个口号“人生苦短,我用python”,但是方便至于,也带来速度上的问题。python最被人诟病的就是程序的运行速度了,所以结合c的快速和python的方便,就诞生了很多解决方案。首先注意到python就是c写成的,所以最根本的解决方案就是利用原生的python c api来写c程序,然后编译成链接库文件(linux下就是so文件),然后在python中直接调用,而且其他的解决方案也基本是围绕这个思路,只不过替你做了很多重复的工作。这次主要是简要介绍下python c apiswig,sip,ctypescythoncffi的使用。



python c api

首先来看最原始的就是使用python c api了。

  1. #include <Python.h>
  2.  
  3. staticPyObject*add(PyObject*self, PyObject*args){
  4.    inta=0;
  5.    intb=0;
  6.    if(!PyArg_ParseTuple(args,”i|i”,&a,&b))
  7.        returnNULL;
  8.    returnPy_BuildValue(“i”, a+b);
  9. }
  10.  
  11. staticPyObject*sub(PyObject*self, PyObject*args){
  12.    inta=0;
  13.    intb=0;
  14.    if(!PyArg_ParseTuple(args,”i|i”,&a,&b))
  15.        returnNULL;
  16.    returnPy_BuildValue(“i”, a-b);
  17. }
  18.  
  19. staticPyMethodDef addMethods[]={
  20.    {“add”, add, METH_VARARGS},
  21.    {“sub”, sub, METH_VARARGS},
  22.    {NULL,NULL,0,NULL}
  23. };
  24.  
  25. voidinitmytest(){
  26.     Py_InitModule(“mytest”, addMethods);
  27. }

首先是引入Python.h这个头文件,所以编译的时候要注意引入python的库,python中的对象在c中都是用PyObject来表示的,程序中定义了add和sub两个方法,然后编写init函数,名字注意是init加上你的module的名字,然后调用Py_InitModule函数来告诉python你定义的函数有哪些。然后就是把他编译成so文件。

  1. gcc mytest.c -shared -lpython2.7 -L /usr/lib/python2.7/ -I /usr/include/python2.7/ -o mytest.so

这样你就可以在python中import mytest这样引用,用法就和用其他python的模块一样了。



swig

首先要说明的是swig可以进行很多语言的调用转换,不止是可以让python调用c。swig和sip都被称作wrapper,就是说他对你的原有函数进行了包装。看到之前用python c api的方式里,我们必须严格按照python c api的方式来写代码,破坏了原有c程序的可读性,于是wrapper的思想就是把原生c程序包装成python c api那种方式的代码,再去生成so文件。因此我们要做的是首先写c文件。

  1. intadd(inta,intb){
  2.    returna+b;
  3. }
  4. intsub(inta,intb){
  5.    returna-b;
  6. }

然后再去写一个swig格式的接口文件。

  1. %module mytest
  2. %{
  3. extern int add(int a, int b);
  4. extern int sub(int a, int b);
  5. %}
  6.  
  7. extern int add(int a, int b);
  8. extern int sub(int a, int b);

然后就可以运行swig,他会自动生成python c api写的代码,并且会自动编译出so文件来调用。



sip

来看sip,sip是swig发展而来是方便python调用c的,所以基本使用方式都是差不多,只不过接口文件略有差异。

  1. %Module(name=mytest, language=”C”)
  2. int add(int a, int b);
  3. int sub(int a, int b);



ctypes

ctypes提供了另外的思路来调用c程序。首先ctypes是python的标准库,所以如果用ctypes你不需要额外的其他的东西。ctypes让你可以在python直接写代码加载c的链接库so文件来调用,就是说如果你用so文件而没有源文件的话,你仍然可以用ctypes去调用。

  1. fromctypesimport*
  2.  
  3. f =’mytest.so’
  4. cdll.LoadLibrary(f)
  5. api = CDLL(f)
  6. api.add.argtypes=[c_int, c_int]
  7. api.add.restype= c_int
  8. api.sub.argtypes=[c_int, c_int]
  9. api.sub.restype= c_int
  10.  
  11. printapi.add(3,2)
  12. printapi.sub(3,2)

有点像在python中去写接口文件,由于是python的标准库,所以这种方式用的还是蛮多的。



cython

cython的方法呢是利用类似python的语法来写调用c程序的接口,并且可以同时方便的地用c函数和python函数。看代码理解。

  1. intsub(inta,intb){
  2.    returna-b;
  3. }

我们可以有一些c写成的代码。

  1. cdef externfrom’test.c’:
  2.    intsub(inta,intb)
  3.  
  4. defadd(inta,intb):
  5.    returna+b
  6.  
  7. defmysub(a, b):
  8.    returnsub(a, b)

然后在cython中我们既可以引入c文件调用c文件中的函数,也可以去调用python中的函数,调用cython程序会把他变成纯正的c文件,然后编译成so文件就可以使用了。



cffi

最后是cffi,cffi类似于ctypes直接在python程序中调用c程序,但是比ctypes更方便不要求编译成so再调用,注意到上面的所有方式都是需要去编译成so文件后再在python中调用,而cffi允许你直接调用c文件来使用里面的函数了,为什么这么神奇呢,其实是cffi在解释过程中才帮你把c编译为so文件的。。。

  1. fromcffiimportFFI
  2. ffi = FFI()
  3. ffi.cdef(“””
  4. int add(int a, int b);
  5. int sub(int a, int b);
  6. “””)
  7. lib = ffi.verify(‘#include “mytest.c”‘)
  8. printlib.add(1,2)

然后基本就是这样了,最后给我的感觉就是:基本上原生的python c api的写法最麻烦了,但是一些需要高级用法的话还是这个更容易控制;方便一点的就是用wrapper;ctypes好处是,他是python的标准模块并且不需要另外写其他的额外程序(接口程序之类的);cython好处就是可以方便的同时调用c函数和python函数,并且是类python语法,用起来很方便;CFFI好处是调用c更加方便,不用编译 so。最后本文只是对各种用法简单的介绍,并没有深入的对各种用法的优缺点进行比较,因此如果想了解更多内容还是去看官方文档吧。。。

我猜您可能还会喜欢:


0

   

0

IT 牛人博客聚合网站(udpwork.com) 聚合
|
评论: 0
|
10000+ 本编程/Linux PDF/CHM 电子书下载

from IT牛人博客聚合网站: http://www.udpwork.com/item/8187.html

Written by cwyalpha

十月 8, 2012 在 3:00 上午

发表在 Uncategorized

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: