之前使用了手动的方法对 C
程序进行编译,而 Cython
则简化了这个过程。
考虑之前的斐波拉契数列,Python
版本:
def fib(n):
a,b = 1,1
for i in range(n):
a,b = a+b, a
return a
C
版本:
int fib(int n) {
int tmp, i, a, b;
a = b = 1;
for (i=0; i<n; i++) {
tmp = a; a += b; b = tmp;
}
return a;
}
Cython
版本:
def fib(int n):
cdef int i, a, b
a,b = 1,1
for i in range(n):
a,b = a+b, a
return a
这里 cdef
定义了 C
变量的类型。
Cython 的好处在于,我们使用了 Python 的语法,又有 C/C++ 的效率,同时省去了之前直接编译成扩展模块的麻烦,并且提供了原生的 Numpy 支持。
其主要用法有两点:
导入 Cython
magic
命令:
%load_ext Cython
使用 magic
命令执行 Cython
:
%%cython
def cyfib(int n):
cdef int i, a, b
a,b = 1,1
for i in range(n):
a,b = a+b, a
return a
cyfib(10)
Cython
代码以 .pyx
结尾,先通过 cython 转化为 .c
文件,再用 gcc
转化为 .so(.pyd)
文件。
%%file fib.pyx
def cyfib(int n):
cdef int i, a, b
a,b = 1,1
for i in range(n):
a,b = a+b, a
return a
%%file setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext = Extension("fib", sources=["fib.pyx"])
setup(ext_modules=[ext], cmdclass={'build_ext': build_ext})
编译成功:
!python setup.py build_ext --inplace
使用模块:
import fib
fib.cyfib(10)
import zipfile
f = zipfile.ZipFile('07-03-fib.zip','w',zipfile.ZIP_DEFLATED)
names = 'fib.pyd fib.pyx fib.c setup.py'.split()
for name in names:
f.write(name)
f.close()
清理之前生成的文件:
!rm -f fib.pyd
!rm -f fib.pyc
!rm -f fib.C
清理之前导入的模块:
%reset -f
使用 pyximport
:
import pyximport
pyximport.install()
import fib
fib.cyfib(10)
install
函数会自动检测 Cython 程序的变化,并自动导入,不过一般用于简单文件的编译。
清理生成的文件:
!rm -f setup*.*
!rm -f fib.*
!rm -rf build