Cython:Cython 基础,将源代码转换成扩展模块

Cython 基础

之前使用了手动的方法对 C 程序进行编译,而 Cython 则简化了这个过程。

考虑之前的斐波拉契数列,Python 版本:

  1. def fib(n):
  2. a,b = 1,1
  3. for i in range(n):
  4. a,b = a+b, a
  5. return a

C 版本:

  1. int fib(int n) {
  2. int tmp, i, a, b;
  3. a = b = 1;
  4. for (i=0; i<n; i++) {
  5. tmp = a; a += b; b = tmp;
  6. }
  7. return a;
  8. }

Cython 版本:

  1. def fib(int n):
  2. cdef int i, a, b
  3. a,b = 1,1
  4. for i in range(n):
  5. a,b = a+b, a
  6. return a

这里 cdef 定义了 C 变量的类型。

Cython 的好处在于,我们使用了 Python 的语法,又有 C/C++ 的效率,同时省去了之前直接编译成扩展模块的麻烦,并且提供了原生的 Numpy 支持。

官方网址:http://www.cython.org

其主要用法有两点:

  • 将 Python 程序转化为 C 程序
  • 包装 C/C++ 程序

将源代码转换成扩展模块

ipython 中使用 Cython 命令

导入 Cython magic 命令:

In [1]:

  1. %load_ext Cython

使用 magic 命令执行 Cython

In [2]:

  1. %%cython
  2. def cyfib(int n):
  3. cdef int i, a, b
  4. a,b = 1,1
  5. for i in range(n):
  6. a,b = a+b, a
  7. return a

In [3]:

  1. cyfib(10)

Out[3]:

  1. 144

使用 distutils 编译 Cython

Cython 代码以 .pyx 结尾,先通过 cython 转化为 .c 文件,再用 gcc 转化为 .so(.pyd) 文件。

In [4]:

  1. %%file fib.pyx
  2. def cyfib(int n):
  3. cdef int i, a, b
  4. a,b = 1,1
  5. for i in range(n):
  6. a,b = a+b, a
  7. return a
  1. Writing fib.pyx

In [5]:

  1. %%file setup.py
  2. from distutils.core import setup
  3. from distutils.extension import Extension
  4. from Cython.Distutils import build_ext
  5.  
  6. ext = Extension("fib", sources=["fib.pyx"])
  7.  
  8. setup(ext_modules=[ext], cmdclass={'build_ext': build_ext})
  1. Overwriting setup.py

编译成功:

In [6]:

  1. !python setup.py build_ext --inplace
  1. running build_ext
  2. cythoning fib.pyx to fib.c
  3. building 'fib' extension
  4. creating build
  5. creating build\temp.win-amd64-2.7
  6. creating build\temp.win-amd64-2.7\Release
  7. 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
  8. writing build\temp.win-amd64-2.7\Release\fib.def
  9. 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]:

  1. import fib
  2.  
  3. fib.cyfib(10)

Out[7]:

  1. 144

In [8]:

  1. import zipfile
  2.  
  3. f = zipfile.ZipFile('07-03-fib.zip','w',zipfile.ZIP_DEFLATED)
  4.  
  5. names = 'fib.pyd fib.pyx fib.c setup.py'.split()
  6. for name in names:
  7. f.write(name)
  8.  
  9. f.close()

使用 pyximport

清理之前生成的文件:

In [9]:

  1. !rm -f fib.pyd
  2. !rm -f fib.pyc
  3. !rm -f fib.C

清理之前导入的模块:

In [10]:

  1. %reset -f

使用 pyximport

In [11]:

  1. import pyximport
  2. pyximport.install()
  3.  
  4. import fib
  5.  
  6. fib.cyfib(10)

Out[11]:

  1. 144

install 函数会自动检测 Cython 程序的变化,并自动导入,不过一般用于简单文件的编译。

清理生成的文件:

In [12]:

  1. !rm -f setup*.*
  2. !rm -f fib.*
  3. !rm -rf build

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/07-interfacing-with-other-languages/07.03-cython-part-1.ipynb