Cython代碼和Python代碼區別__Python

來源:互聯網
上載者:User

代碼運行在IPython-Notebook中,在IPython-Notebook中匯入cython環境。

1
%load_ext cython

Cython可以在Python中摻雜C和C++的靜態類型,cython編譯器可以把Cython源碼編譯成C或C++代碼,編譯後的代碼可以單獨執行或者作為Python中的模型使用。Cython中的強大之處在於可以把Python和C結合起來,它使得看起來像Python語言的Cython代碼有著和C相似的運行速度。

我們使用一個簡單的Fibonacci函數來比較下Python和Cython的區別:

123456
#pythondef fib1(n):    a,b=0.0,1.0    for i in range(n):        a,b=a+b,a    return a

下面代碼使用%%cython標誌表示下面的代碼使用cython編譯

1234567
%%cythondef fib2(int n):    cdef double a=0.0, b=1.0    for i in range(n):        a,b = a+b,a    return a

通過比較上面的代碼,為了把Python中的動態類型轉換為Cython中的靜態類型,我們用cdef來定義C語言中的變數i,a,b。
我們用C語言實現Fibonacci函數,然後通過Cython用Python封裝,其中cfib.h為Fibonacci函數C語言實現,如下:

12345678
double cfib(int n) {  int i;  double a=0.0, b=1.0, tmp;  for (i=0; i<n; ++i) {    tmp = a; a = a + b; b = tmp;  }  return a;}

1234567
%%cythoncdef extern from "/home/ldy/MEGA/python/cython/cfib.h":    double cfib(int n)  def fib3(n):    """Returns the nth Fibonacci number."""    return cfib(n)

比較不同方法的已耗用時間:

123456
%timeit result=fib1(1000)%timeit result=fib2(1000)%timeit result=fib3(1000)
10000 loops, best of 3: 73.6 µs per loop1000000 loops, best of 3: 1.94 µs per loop1000000 loops, best of 3: 1.92 µs per loop
Cython代碼的編譯

Cython代碼的編譯為Python可調用模組的過程主要分為兩步:第一步是cython編譯器把Cython代碼最佳化成C或C++代碼;第二步是使用C或C++編譯器編譯產生的C或C++代碼得到Python可調用的模組。

我們通過一個setup.py指令碼來編譯上面寫的fib.pyxCython代碼,如下所示,關鍵就在第三行,cythonize函數的作用是通過cython編譯器把Cython代碼轉換為C代碼,setup函數則是把產生的C代碼轉換成Python可調用模組。

1234
from distutils.core import setupfrom Cython.Build import cythonizesetup(ext_modules=cythonize('fib.pyx'))#setup(ext_modules=cythonize('*.pyx','fib1.pyx'))也可以一次編譯多個Cython檔案

寫好setup.py檔案後,就可以通過下述命令執行編譯:

1
python setup.py build_ext --inplace

執行後產生了fib.c代碼以及fib.so檔案,以及一些中間結果儲存在build檔案夾裡。

1234
import osos.chdir('/home/ldy/MEGA/python/cython/test')os.getcwd()!ls
build  fib.c  fib.pyx  fib.so  setup.py

通過Python調用產出的fib.so模組:

12
import fibfib.fib2(90)
2.880067194370816e+18
Cython中類型的定義

為什麼Cython和Python比會提高很多效能,主要原因有兩點:一是Python是解釋型語言,在運行之前Python解譯器把Python代碼解釋成Python位元組碼運行在Python虛擬機器上,Python虛擬機器把Python位元組碼最終翻譯成CPU能執行的機器碼;而Cython代碼是事先直接編譯成可被Python調用的機器碼,在運行時可直接執行。第二個主要的原因是Python是動態類型,Python解譯器在解釋時需要判斷類型,然後再提取出底層能夠啟動並執行資料以及操作;然而C語言等比較底層的語言是靜態類型,編譯器直接提取資料進行操作產生機器碼。

Cython中使用cdef來定義靜態類型:

123
cdef int icdef int jcdef float f

也可以一次定義多個:

1234
cdef:    int i    int j    float f

Cython中還允許在靜態類型和動態類型同時存在及相互賦值:

123456
%%cythoncdef int a=1,b=2,c=3list_of_ints=[a,b,c]list_of_ints.append(4)a=list_of_ints[1]print a,list_of_ints
2 [1, 2, 3, 4]

聲明Python類型為靜態類型,Cython支援把一些Python內建的如list,tuple,dict等型別宣告為靜態類型,這樣聲明使得它們能像正常Python類型一樣使用,但是需要約束成只能是他們所申明的類型,不能隨意變動。

12345678910111213
%%cythoncdef:    list names    dict name_numname_num={'jerry':1,'Tom':2,'Bell':3}names=list(name_num.keys())print namesother_names=names#動態類型可以從靜態類型的Python對象初始化del other_names[0]#因為引用了同一個list,所以都會刪除第一個元素print names,other_namesother_names=tuple(other_names)#names和other_names的區別在於names只能是list類型,print other_names           #other_names可以引用任何類型
['Bell', 'jerry', 'Tom']['jerry', 'Tom'] ['jerry', 'Tom']('jerry', 'Tom')
Cython中numpy的使用

我們先構造一個函數來測試下使用純Python時的運算時間來做對比,這個函數的作用是對一副輸入映像求梯度(不必過分關注函數的功能,在這隻是使用這個函數作為測試)。函數的輸入資料是indata一個像素為1400*1600的圖片;輸出為outdata,為每個像素梯度值,下面是這個函數的純Python實現:

123456789

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.