Cython 是 Python 编程语言的编译器,旨在优化性能并形成扩展的 Cython 编程语言。 作为 Python 的扩展,Cython 也是 Python 语言的超集,它支持调用 C 函数以及在变量和类属性上声明 C 类型。 这使得包装外部 C 库、将 C 嵌入到现有应用程序中,或者用像 Python 本身一样简单的语法为 Python 编写 C 扩展变得容易。
Cython 通常用于创建 C 模块,以加快 Python 代码的执行速度。 这在解释型语言效率不高的复杂应用程序中非常重要。
安装 Cython
您可以使用 Python 在 Linux、BSD、Windows 或 macOS 上安装 Cython
$ python -m pip install Cython
安装完成后,即可使用。
将 Python 转换为 C
使用 Cython 的一个好方法是从一个简单的“hello world”应用程序开始。 这不是 Cython 优势的最佳演示,但它显示了使用 Cython 时会发生什么。
首先,在名为 hello.pyx
的文件中创建这个简单的 Python 脚本(.pyx
扩展名不是神奇的,理论上它可以是任何东西,但它是 Cython 的默认扩展名)
print("hello world")
接下来,创建一个 Python 安装脚本。 setup.py
文件就像 Python 版本的 makefile,Cython 可以使用它来处理您的 Python 代码
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("hello.pyx")
)
最后,使用 Cython 将您的 Python 脚本转换为 C 代码
$ python setup.py build_ext --inplace
您可以在您的项目目录中看到结果。 Cython 的 cythonize
模块将 hello.pyx
转换为 hello.c
文件和一个 .so
库。 C 代码有 2,648 行,因此它比单行 hello.pyx
源代码多得多。 .so
库也比其源文件大 2,000 多倍(54,000 字节比 20 字节)。 再次说明,运行单个 Python 脚本需要 Python,因此有很多代码支持单行 hello.pyx
文件。
要使用 C 代码版本的 Python “hello world” 脚本,打开一个 Python 提示符并导入您创建的新的 hello
模块
>>> import hello
hello world
将 C 代码集成到 Python 中
计算素数是计算能力的一个很好的通用测试。 素数是大于 1 的正数,仅当除以 1 或自身时才会产生正整数。 理论上很简单,但随着数字变大,计算要求也会增加。 在纯 Python 中,可以在 10 行代码内完成
import sys
number = int(sys.argv[1])
if not number <= 1:
for i in range(2, number):
if (number % i) == 0:
print("Not prime")
break
else:
print("Integer must be greater than 1")
此脚本在成功时保持沉默,如果该数字不是素数则返回一条消息
$ ./prime.py 3
$ ./prime.py 4
Not prime.
将其转换为 Cython 需要做一些工作,部分原因是使代码适合用作库,部分原因是出于性能考虑。
脚本和库
许多用户将 Python 作为一种脚本语言来学习:您告诉 Python 您希望它执行的步骤,然后它会完成这项工作。 当您更多地了解 Python(以及一般的开源编程)时,您会了解到,那里最强大的代码大多存在于其他应用程序可以利用的库中。 您的代码越不具体,程序员(包括您)就越有可能将其重新用于其他应用程序。 将计算与工作流程分离可能需要更多的工作,但最终通常值得付出努力。
对于这个简单的素数计算器,将其转换为 Cython 从一个安装脚本开始
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("prime.py")
)
将您的脚本转换为 C
$ python setup.py build_ext --inplace
到目前为止一切似乎都运行良好,但是当您尝试导入和使用您的新模块时,您会收到一个错误
>>> import prime
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "prime.py", line 2, in init prime
number = sys.argv[1]
IndexError: list index out of range
问题在于 Python 脚本期望从终端运行,在这种情况下,参数(在这种情况下,是要测试为素数的整数)很常见。 您需要修改您的脚本,使其可以用作库。
编写一个库
库不使用系统参数,而是接受来自其他代码的参数。 不要使用 sys.argv
来引入用户输入,而是将您的代码变成一个接受名为 number
(或 num
或您喜欢的任何变量名)的参数的函数
def calculate(number):
if not number <= 1:
for i in range(2, number):
if (number % i) == 0:
print("Not prime")
break
else:
print("Integer must be greater than 1")
不可否认的是,这使得您的脚本难以测试,因为当您在 Python 中运行代码时,永远不会执行 calculate
函数。 但是,Python 程序员已经设计了一种常见的(如果不是直观的)解决方法。 当 Python 解释器执行 Python 脚本时,会有一个名为 __name__
的特殊变量,它会被设置为 __main__
,但是当它作为模块导入时,__name__
会被设置为模块的名称。 通过利用这一点,您可以编写一个既是 Python 模块又是有效的 Python 脚本的库
import sys
def calculate(number):
if not number <= 1:
for i in range(2, number):
if (number % i) == 0:
print("Not prime")
break
else:
print("Integer must be greater than 1")
if __name__ == "__main__":
number = sys.argv[1]
calculate( int(number) )
现在您可以将代码作为命令运行
$ python ./prime.py 4
Not a prime
您可以将其转换为 Cython 以用作模块
>>> import prime
>>> prime.calculate(4)
Not prime
C Python
使用 Cython 将代码从纯 Python 转换为 C 可能很有用。 本文演示了如何执行该部分,但 Cython 还有一些功能可以帮助您在转换之前优化代码,一些选项可以分析您的代码以查找 Cython 何时与 C 交互等等。 如果您正在使用 Python,但您希望使用 C 代码来增强您的代码,或者进一步了解库如何提供比脚本更好的可扩展性,或者您只是对 Python 和 C 如何协同工作感到好奇,那么就开始尝试 Cython 吧。
1 条评论