python的c語言擴展方法簡介

原文地址:[http://www.isnowfy.com/introduction-to-python-c-extension/
java

python是一門很是方便的動態語言,不少你用c或者java要不少行的代碼,可能python幾行就搞定了,因此python社區一直有個口號 「人生苦短,我用python」,可是方便至於,也帶來速度上的問題。python最被人詬病的就是程序的運行速度了,因此結合c的快速和python的 方便,就誕生了不少解決方案。首先注意到python就是c寫成的,因此最根本的解決方案就是利用原生的python c api來寫c程序,而後編譯成連接庫文件(linux下就是so文件),而後在python中直接調用,並且其餘的解決方案也基本是圍繞這個思路,只不過 替你作了不少重複的工做。此次主要是簡要介紹下python c apiswig,sip,ctypescythoncffi的使用。


python

python c api

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

  1. #include <Python.h>api

  2.  

  3. static PyObject* add(PyObject* self, PyObject* args){app

  4.     int a = 0;python2.7

  5.     int b = 0;函數

  6.     if(!PyArg_ParseTuple(args, "i|i", &a, &b))ui

  7.         return NULL;spa

  8.     return Py_BuildValue("i", a+b);rest

  9. }

  10.  

  11. static PyObject* sub(PyObject* self, PyObject* args){

  12.     int a = 0;

  13.     int b = 0;

  14.     if(!PyArg_ParseTuple(args, "i|i", &a, &b))

  15.         return NULL;

  16.     return Py_BuildValue("i", a-b);

  17. }

  18.  

  19. static PyMethodDef addMethods[]={

  20.     {"add", add, METH_VARARGS},

  21.     {"sub", sub, METH_VARARGS},

  22.     {NULL, NULL, 0, NULL}

  23. };

  24.  

  25. void initmytest(){

  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. int add(int a, int b){

  2.     return a+b;

  3. }

  4. int sub(int a, int b){

  5.     return a-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. from ctypes import *

  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. print api.add(3, 2)

  12. print api.sub(3, 2)

有點像在python中去寫接口文件,因爲是python的標準庫,因此這種方式用的仍是蠻多的。


cython

cython的方法呢是利用相似python的語法來寫調用c程序的接口,而且能夠同時方便的地用c函數和python函數。看代碼理解。

  1. int sub(int a, int b){

  2.     return a-b;

  3. }

咱們能夠有一些c寫成的代碼。

  1. cdef extern from 'test.c':

  2.     int sub(int a, int b)

  3.  

  4. def add(int a, int b):

  5.     return a+b

  6.  

  7. def mysub(a, b):

  8.     return sub(a, b)

而後在cython中咱們既能夠引入c文件調用c文件中的函數,也能夠去調用python中的函數,調用cython程序會把他變成純正的c文件,而後編譯成so文件就可使用了。

from cffi import FFI
ffi = FFI()
ffi.cdef("""
int add(int a, int b);
int sub(int a, int b);
""")
lib = ffi.verify('#include "mytest.c"')
print lib.add(1,2)

最後是cffi,cffi相似於ctypes直接在python程序中調用c程序,可是比ctypes更方便不要求編譯成so再調用,注意到上面的 全部方式都是須要去編譯成so文件後再在python中調用,而cffi容許你直接調用c文件來使用裏面的函數了,爲何這麼神奇呢,實際上是cffi在解 釋過程當中才幫你把c編譯爲so文件的。。。

而後基本就是這樣了,最後給個人感受就是:基本上原生的python c api的寫法最麻煩了,可是一些須要高級用法的話仍是這個更容易控制;方便一點的就是用wrapper;ctypes好處是,他是python的標準模塊 而且不須要另外寫其餘的額外程序(接口程序之類的);cython好處就是能夠方便的同時調用c函數和python函數,而且是類python語法,用起 來很方便;CFFI好處是調用c更加方便,不用編譯 so。最後本文只是對各類用法簡單的介紹,並無深刻的對各類用法的優缺點進行比較,所以若是想了解更多內容仍是去看官方文檔吧。。。

相關文章
相關標籤/搜索