Cython:Cython 基础,将源代码转换成扩展模块
Cython 基础
之前使用了手动的方法对 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 支持。
其主要用法有两点:
- 将 Python 程序转化为 C 程序
- 包装 C/C++ 程序
将源代码转换成扩展模块
ipython 中使用 Cython 命令
导入 Cython
magic
命令:
In [1]:
- %load_ext Cython
使用 magic
命令执行 Cython
:
In [2]:
- %%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
In [3]:
- cyfib(10)
Out[3]:
- 144
使用 distutils 编译 Cython
Cython
代码以 .pyx
结尾,先通过 cython 转化为 .c
文件,再用 gcc
转化为 .so(.pyd)
文件。
In [4]:
- %%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
- Writing fib.pyx
In [5]:
- %%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})
- Overwriting setup.py
编译成功:
In [6]:
- !python setup.py build_ext --inplace
- running build_ext
- cythoning fib.pyx to fib.c
- building 'fib' extension
- creating build
- creating build\temp.win-amd64-2.7
- creating build\temp.win-amd64-2.7\Release
- C:\Miniconda\Scripts\gcc.bat -DMS_WIN64 -mdll -O -Wall -IC:\Miniconda\include -IC:\Miniconda\PC -c fib.c -o build\temp.win-amd64-2.7\Release\fib.o
- writing build\temp.win-amd64-2.7\Release\fib.def
- C:\Miniconda\Scripts\gcc.bat -DMS_WIN64 -shared -s build\temp.win-amd64-2.7\Release\fib.o build\temp.win-amd64-2.7\Release\fib.def -LC:\Miniconda\libs -LC:\Miniconda\PCbuild\amd64 -lpython27 -lmsvcr90 -o "C:\Users\Jin\Documents\Git\python-tutorial\07. interfacing with other languages\fib.pyd"
使用模块:
In [7]:
- import fib
- fib.cyfib(10)
Out[7]:
- 144
In [8]:
- 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()
使用 pyximport
清理之前生成的文件:
In [9]:
- !rm -f fib.pyd
- !rm -f fib.pyc
- !rm -f fib.C
清理之前导入的模块:
In [10]:
- %reset -f
使用 pyximport
:
In [11]:
- import pyximport
- pyximport.install()
- import fib
- fib.cyfib(10)
Out[11]:
- 144
install
函数会自动检测 Cython 程序的变化,并自动导入,不过一般用于简单文件的编译。
清理生成的文件:
In [12]:
- !rm -f setup*.*
- !rm -f fib.*
- !rm -rf build