基础教程 | 您所在的位置:网站首页 › Python的中文教程 › 基础教程 |
基础教程
Cython 的基础
Cython 的本质可以总结如下:Cython 是包含 C 数据类型的 Python。 Cython 是 Python:几乎所有 Python 代码都是合法的 Cython 代码。 (存在一些限制,但是差不多也可以。) Cython 的编译器会转化 Python 代码为 C 代码,这些 C 代码均可以调用 Python/C 的 API。 Cython 可不仅仅包含这些,Cython 中的参数和变量还可以以 C 数据类型来声明。代码中的 Python 值和 C 的值可以自由地交叉混合(intermixed)使用, 所有的转化都是自动进行。Python 中的引用计数维护(Reference count maintenance)和错误检查(error checking)操作同样是自动进行的,并且全面支持 Python 的异常处理工具(facilities),包括 try-except 和 try-finally,即便在其中操作 C 数据都是可以的。 Cython 的 Hello World由于 Cython 能接受几乎所有的合法 Python 源文件,开始使用 Cython 的最难的事情之一是怎么编译你的拓展(extension)。 那么,让我们从典型的(canonical)Python hello world 开始: print "Hello World"将代码保存在文件 helloworld.pyx 中。现在,我们需要创建 setup.py,它是一个类似 Python Makefile 的文件(更多信息请看源文件和编译过程)。 你编写的 setup.py 应该看起来类似这样: from distutils.core import setup from Cython.Build import cythonize setup( ext_modules = cythonize("helloworld.pyx") )输入如下命令来构建你的 Cython 文件: $ python setup.py build_ext --inplace运行完上述命令会在你的当前目录生成一个新文件,如果你的系统是 Unix,文件名为 helloworld.so,如果你的系统是 Windows,文件名为 helloworld.pyd。现在我们用一用刚生成的文件:打开 Python 的解释器(interpreter),像 import 普通文件一样直接 import 你刚生成的文件: >>> import helloworld Hello World恭喜!你已经学会了怎样构建 Cython 的拓展了。但是到现在为止,这个例子并没有给我们一个使用 Cython 的理由。所以,让我们创建一个更现实的例子。 pyximport:Cython 简单编译如果你的模块不需要额外的 C 库活特殊的构件安装,那你可以在 import 时使用 Paul Prescod 和 Stefan Behnel 编写的 pyximport 模块来直接读取 .pyx 文件,而不需要编写 setup.py 文件。 它随同 Cython 一并发布和安装,你可以这样使用它: >>> import pyximport; pyximport.install() >>> import helloworld Hello World自 Cython 0.11 起,pyximport 模块同样实验性地支持普通 Python 模块的编译了。它允许你在所有 Python import 的 .pyx 和 .py 模块上自动运行 Cython,包括哪些标准库和第三方库。但是,任然有不少 Python 模块 Cython 无法编译,遇到这种情况 import 机制(mechanism)会退回去读取 Python 原模块。.py 的 import 机制可按如下方式安装: >>> pyximport.install(pyimport = True) 斐波那契(Fibonacci)函数Python 的官方教程中斐波那契函数是这样定义的: def fib(n): """Print the Fibonacci series up to n.""" a, b = 0, 1 while b < n: print b, a, b = b, a + b现在,我们模仿 Hello World 例子中的步骤,第一步将 Python 官方教程中斐波那契函数文件名改为.pyx,例如 fib.pyx,然后我们创建 setup.py 文件。你只需要修改一下 Cython 文件的文件名和生成模块的名字就可以直接复用 Hello World 例子中的 setup.py 文件。这样,我们有了这么个文件: from distutils.core import setup from Cython.Build import cythonize setup( ext_modules=cythonize("fib.pyx"), )使用和 helloworld.pyx 一样的命令来构建该拓展: $ python setup.py build_ext --inplace使用新的拓展: >>> import fib >>> fib.fib(2000) 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 质数(Primes)本段给出一个小例子来展示一些我们可以做的事。这个例子给出一个用来寻找质数的程序。你告诉它你需要多少个质数,程序以 Python list 的形式将这些质数返回给你。 primes.pyx: def primes(int kmax): cdef int n, k, i cdef int p[1000] result = [] if kmax > 1000: kmax = 1000 k = 0 n = 2 while k < kmax: i = 0 while i < k and n % p[i] != 0: i = i + 1 if i == k: p[k] = n k = k + 1 result.append(n) n = n + 1 return result可以从上面的代码中看出,除了参数 kmax 是以 int 类型声明的外,代码和普通 Python 函数定义一样。这意味着传入 kmax 的对象将会转化成 C 语言的整数变量。(如果无法转化为 int 型,将会抛出 TypeError 异常)。 第 2、3 行使用了 cdef 来定义 C 语言的局部变量。第 4 行创建了一个用来返回结果的 Python list。注意,代码的编写和 Python 代码的编写一模一样。因为结果变量还没给定类型,它只是用来储存 Python 对象。 第 7-9 行配置了一个循环用来测试候选数字是否是质数,一直到找到了足够多的质数为止。第 11-12 行用候选数字除以已经找到的质数,这两行很有意思. 因为没有涉及 Python 对象,所以循环将会完全翻译为 C 语言代码,所以运行非常快! 当一个质数被找到,第 14-15 行会将其添加到队列 p 中,以便在循环中检测质数时用来快速检索,第 16 行将其添加到结果队列中。第 16 行看起来也非常类似 Python 代码,它也的确是 Python 代码,在 twist 的作用下 C 语言定义的变量 n 在 append 方法调用前会自动转化为 Python 对象。最后,在第 18 行通过普通的 Python return 命令返回结果队列。 使用 Cython 编译器编译 primes.pyx 文件来生成一个拓展模块,我们可以在互动解释器(interactive interpreter)中来试用: >>> import primes >>> primes.primes(10) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]正常运行!如果你好奇 Cython 为你节约了多少资源,可以看看这个模块生成的 C 代码。 语言细节想要获取更多地 Cython 语言信息,请看 Language Basics。 想在数字计算中运用 Cython 请看 Cython for NumPy Users。 |
CopyRight 2018-2019 实验室设备网 版权所有 |