Cython与pyx pyd格式-python调用c++

1、python与C++为何要结合

当从事技术的人员提到 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 的能力,包括:

  • 编写可在任何时候来回调用本地 C/C ++ 代码的 Python 代码;
  • 通过添加静态类型声明,轻松将可读 Python 代码调整为纯 C 性能;
  • 使用组合源代码级调试,查找你 Python、Cython 及 C 代码中的 Bugs;
  • 与大数据集高效交互,譬如:使用多维 NumPy 数组;
  • 在大型、成熟、广泛使用的 CPython 生态系统中,快速构建你的应用程序;
  • 从传统、低级或高性能库、应用程序,集成本地现有代码。

Cython 语言是支持调用本地 C 函数、C++ 类操作和在变量、类属性基础之上声明 C 类型的可选静态类型的 Python 语言超集,几乎所有 Python 代码都是有效 Cython 代码。

2、pyx与pyd

pyx
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 文件

.pxd 文件是由 Cython 编程语言 “编写” 而成的 Python 扩展模块头文件。

.pxd 文件类似于 C 语言的 .h 头文件,.pxd 文件中有 Cython 模块要包含的 Cython 声明 (或代码段)。

.pxd 文件可共享外部 C 语言声明,也能包含 C 编译器内联函数。.pxd 文件还可为 .pyx 文件模块提供
Cython 接口,以便其它 Cython 模块可使用比 Python 更高效的协议与之进行通信。

可用 cimport 关键字将 .pxd 文件导入 .pyx 模块文件中。

pyd

.pyd 文件是非Python,由其它编程语言 “编写-编译” 生成的 Python 扩展模块。

.pyd是二进制文件,只能反编译查看,本质上就是DLL文件。

Python 要导入 .pyd 文件,实际上是在 .pyd 文件中封装了一个 module。在 python 中使用时,把它当成 module 来用就可以了,即:“import 路径名.modulename” 即可,路径名为 .pyd 文件所在的路径。

3、编译

最近在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

猜你喜欢

转载自blog.csdn.net/NCU_wander/article/details/123908387