python的c语言扩展方法简介
2019獨角獸企業重金招聘Python工程師標準>>>
原文地址:[http://www.isnowfy.com/introduction-to-python-c-extension/]
python是一門非常方便的動態語言,很多你用c或者java要很多行的代碼,可能python幾行就搞定了,所以python社區一直有個口號 “人生苦短,我用python”,但是方便至于,也帶來速度上的問題。python最被人詬病的就是程序的運行速度了,所以結合c的快速和python的 方便,就誕生了很多解決方案。首先注意到python就是c寫成的,所以最根本的解決方案就是利用原生的python c api來寫c程序,然后編譯成鏈接庫文件(linux下就是so文件),然后在python中直接調用,而且其他的解決方案也基本是圍繞這個思路,只不過 替你做了很多重復的工作。這次主要是簡要介紹下python c api,swig,sip,ctypes,cython,cffi的使用。
python c api
首先來看最原始的就是使用python c api了。
#include <Python.h>
?
static PyObject* add(PyObject* self, PyObject* args){
? ? int a = 0;
? ? int b = 0;
? ? if(!PyArg_ParseTuple(args, "i|i", &a, &b))
? ? ? ? return NULL;
? ? return Py_BuildValue("i", a+b);
}
?
static PyObject* sub(PyObject* self, PyObject* args){
? ? int a = 0;
? ? int b = 0;
? ? if(!PyArg_ParseTuple(args, "i|i", &a, &b))
? ? ? ? return NULL;
? ? return Py_BuildValue("i", a-b);
}
?
static PyMethodDef addMethods[]={
? ? {"add", add, METH_VARARGS},
? ? {"sub", sub, METH_VARARGS},
? ? {NULL, NULL, 0, NULL}
};
?
void initmytest(){
? ? Py_InitModule("mytest", addMethods);
}
首先是引入Python.h這個頭文件,所以編譯的時候要注意引入python的庫,python中的對象在c中都是用PyObject來表示的, 程序中定義了add和sub兩個方法,然后編寫init函數,名字注意是init加上你的module的名字,然后調用Py_InitModule函數來 告訴python你定義的函數有哪些。然后就是把他編譯成so文件。
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文件。
int add(int a, int b){
? ? return a+b;
}
int sub(int a, int b){
? ? return a-b;
}
然后再去寫一個swig格式的接口文件。
%module mytest
%{
extern int add(int a, int b);
extern int sub(int a, int b);
%}
?
extern int add(int a, int b);
extern int sub(int a, int b);
然后就可以運行swig,他會自動生成python c api寫的代碼,并且會自動編譯出so文件來調用。
sip
來看sip,sip是swig發展而來是方便python調用c的,所以基本使用方式都是差不多,只不過接口文件略有差異。
%Module(name=mytest, language="C")
int add(int a, int b);
int sub(int a, int b);
ctypes
ctypes提供了另外的思路來調用c程序。首先ctypes是python的標準庫,所以如果用ctypes你不需要額外的其他的東西。 ctypes讓你可以在python直接寫代碼加載c的鏈接庫so文件來調用,就是說如果你用so文件而沒有源文件的話,你仍然可以用ctypes去調 用。
from ctypes import *
?
f = 'mytest.so'
cdll.LoadLibrary(f)
api = CDLL(f)
api.add.argtypes = [c_int, c_int]
api.add.restype = c_int
api.sub.argtypes = [c_int, c_int]
api.sub.restype = c_int
?
print api.add(3, 2)
print api.sub(3, 2)
有點像在python中去寫接口文件,由于是python的標準庫,所以這種方式用的還是蠻多的。
cython
cython的方法呢是利用類似python的語法來寫調用c程序的接口,并且可以同時方便的地用c函數和python函數。看代碼理解。
int sub(int a, int b){
? ? return a-b;
}
我們可以有一些c寫成的代碼。
cdef extern from 'test.c':
? ? int sub(int a, int b)
?
def add(int a, int b):
? ? return a+b
?
def mysub(a, b):
? ? 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。最后本文只是對各種用法簡單的介紹,并沒有深入的對各種用法的優缺點進行比較,因此如果想了解更多內容還是去看官方文檔吧。。。
轉載于:https://my.oschina.net/u/2306127/blog/369996
總結
以上是生活随笔為你收集整理的python的c语言扩展方法简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET MVC+EF框架+Eas
- 下一篇: linux上部署hadoop集群 HA-