Files
ailearning/docs/da/094.md
2020-10-19 21:08:55 +08:00

244 lines
3.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CythonCython 基础,将源代码转换成扩展模块
## Cython 基础
之前使用了手动的方法对 `C` 程序进行编译,而 `Cython` 则简化了这个过程。
考虑之前的斐波拉契数列,`Python` 版本:
```py
def fib(n):
a,b = 1,1
for i in range(n):
a,b = a+b, a
return a
```
`C` 版本:
```py
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` 版本:
```py
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** 支持。
官方网址:[http://www.cython.org](http://www.cython.org)
其主要用法有两点:
* 将 Python 程序转化为 C 程序
* 包装 C/C++ 程序
## 将源代码转换成扩展模块
### ipython 中使用 Cython 命令
导入 `Cython` `magic` 命令:
In [1]:
```py
%load_ext Cython
```
使用 `magic` 命令执行 `Cython`
In [2]:
```py
%%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]:
```py
cyfib(10)
```
Out[3]:
```py
144
```
### 使用 distutils 编译 Cython
`Cython` 代码以 `.pyx` 结尾,先通过 cython 转化为 `.c` 文件,再用 `gcc` 转化为 `.so(.pyd)` 文件。
In [4]:
```py
%%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
```
```py
Writing fib.pyx
```
In [5]:
```py
%%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})
```
```py
Overwriting setup.py
```
编译成功:
In [6]:
```py
!python setup.py build_ext --inplace
```
```py
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]:
```py
import fib
fib.cyfib(10)
```
Out[7]:
```py
144
```
In [8]:
```py
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]:
```py
!rm -f fib.pyd
!rm -f fib.pyc
!rm -f fib.C
```
清理之前导入的模块:
In [10]:
```py
%reset -f
```
使用 `pyximport`
In [11]:
```py
import pyximport
pyximport.install()
import fib
fib.cyfib(10)
```
Out[11]:
```py
144
```
`install` 函数会自动检测 Cython 程序的变化,并自动导入,不过一般用于简单文件的编译。
清理生成的文件:
In [12]:
```py
!rm -f setup*.*
!rm -f fib.*
!rm -rf build
```