当从事技术的人员提到 Python 的时候,经常会说到下面两个优点:
然而实际上,第一点是以巨慢的执行速度为代价的,这个时候有志之士提出可以将C++与python进行友好的融合,按照 Python 的规范使用 Python API,调用C++乃至于C++内部的库。
因此出现了Cython。Cython 可以让我们方便地用 Python 的语法混合编写 Python 和 C/C++ 代码,提升 Python 速度。但是C语言是编译性语言,而Python则是解释性语言,简而言之,就是Python运行是逐行运行,不需要实现编译,而C需要在运行前编译。
Cython 是为 Python 编程语言编写 C 语言扩展的编译器。Cython 是自由开源的,采用 Apache 授权许可协议。 Cython 是用于 Python 编程语言和 (基于 Pyrex) 扩展 Cython 编程语言的优化静态编译器。Cython 也是基于 Pyrex 的源代码翻译器,但功能更前沿、更优化。Cython 使得为 Python 编写 C 扩展如 Python 本身般容易。Cython 是编写、包裹外部 C/C++ 库胶水代码,将 CPython 嵌入现有应用程序、加速 Python 代码执行的理想 C 模块语言。
Cython 提供了允许你组合 Python 和 C 的能力,包括:
Cython 语言是支持调用本地 C 函数、C++ 类操作和在变量、类属性基础之上声明 C 类型的可选静态类型的 Python 语言超集,几乎所有 Python 代码都是有效 Cython 代码。
PYX file is a Pyrex source.
Pyrex is a Language for Writing Python Extension modules.
Pyrex lets you write code that mixes Python and C data types any way you want, and compiles it into a C extension for Python.
.pyx 文件是由 Cython 编程语言 “编写” 而成的 Python 扩展模块源代码文件。
.pyx 文件类似于 C 语言的 .c 源代码文件,.pyx 文件中有 Cython 模块的相关源代码。
不像 Python 语言可直接解释使用的 .py 文件,.pyx 文件必须先被编译成 .c 文件,再编译成 .pyd (Windows 平台) 或 .so (Linux 平台) 文件,才可作为模块 import 导入使用。
.pxd 文件是由 Cython 编程语言 “编写” 而成的 Python 扩展模块头文件。
.pxd 文件类似于 C 语言的 .h 头文件,.pxd 文件中有 Cython 模块要包含的 Cython 声明 (或代码段)。
.pxd 文件可共享外部 C 语言声明,也能包含 C 编译器内联函数。.pxd 文件还可为 .pyx 文件模块提供
Cython 接口,以便其它 Cython 模块可使用比 Python 更高效的协议与之进行通信。
可用 cimport 关键字将 .pxd 文件导入 .pyx 模块文件中。
.pyd 文件是非Python,由其它编程语言 “编写-编译” 生成的 Python 扩展模块。
.pyd是二进制文件,只能反编译查看,本质上就是DLL文件。
Python 要导入 .pyd 文件,实际上是在 .pyd 文件中封装了一个 module。在 python 中使用时,把它当成 module 来用就可以了,即:“import 路径名.modulename” 即可,路径名为 .pyd 文件所在的路径。
最近在VisTR的实际实践过程中,遇到了比较多的Cython代码实例。在VisTR代码当中,编译命令是:python setup.py build_ext --inplace
。在pycocotools.ytvos包中,有_mask.cpython-38-x86_64-linux-gnu.so包,是可以直接import _mask
调用的。
具体的如何使用,可以看一个简单的例子:
1、编写简单的示例文件pysample.c:
/* 定义普通C语言实现的add() */
int add(int a,int b)
{
return a+b;
}
/* 把普通C语言实现的add()封装成Python可以调用的函数 */
static PyObject *py_add(PyObject *self, PyObject *args) {
int x, y, result;
/* 从 args 里解析实际参数 */
if (!PyArg_ParseTuple(args,"ii", &x, &y)) {
return NULL;
}
/* 调用普通C语言实现的add() */
result = add(x,y);
/* 把 int 转化为 PyObject* */
return Py_BuildValue("i", result);
}
2 编写buildlib.py,内容如下:
from distutils.core import setup, Extension
setup(name='sample',
ext_modules=[
Extension('sample',
['pysample.c'],
include_dirs = ['/some/dir'],
define_macros = [('FOO','1')],
undef_macros = ['BAR'],
library_dirs = ['/usr/local/lib'],
libraries = ['sample']
)
]
)
3 运行如下命令:
python3 buildlib.py build_ext --inplace
会生成:
sample.cpython-39-darwin.so
4 打开python,输入:
import sample
sample.add(1,1)
具体过程可以参考博客将C代码封装成python可以import调用的so