Python扩展(Cython混编)
- 背景介绍:
Cython是一种针对Python语言与Cython扩展语言进行优化的静态编译器。通过编写Cython接口代码,可以让Python代码与C/C++代码无缝衔接,达到为Python加速的目的。当然,也可以完全通过Cython接口重构Python代码,直接提速Python。整个过程可以表示为:首先将Cython接口代码转化为C/C++代码,然后将C/C++代码编译为动态链接库.pyd(Windows下)或.so文件(Linux下),即:
Cython接口代码 $\rightarrow$ C/C++代码 $\rightarrow$ .pyd/.so动态库
如果接口编写得当,通过Python调用该动态库文件较原生Python代码可提速两个量级。
在语法层面,Cython几乎支持所有的Python语法,并且额外加入了一些C/C++的等效写法(提速的关键)。因此,在编写接口代码的时候势必两种写法都会用到,从而造成混乱。本文将主要介绍笔者习惯的Cython接口写法规范,可能会比较抽象。关于语法细节,建议参考官方文档:https://cython.org/
>>>使用规范<<<
- Python接口端:实现Cython与Python之间的交互(支持缺省参数)
- def $\rightarrow$ 函数接口
- cdef class $\rightarrow$ 类接口
此种情况下,类对象中self只能索引已存在的对象,不能直接创建新内容,功能上与this指针基本对标,此即self限制(只能索引已经定义的对象)。
- C++接口端:实现Cython与C++之间的交互(不支持缺省参数)
- cdef $\rightarrow$ 函数接口
- cdef struct $\rightarrow$ 类接口,不支持函数重载
- cdef cppclass $\rightarrow$ 类接口,支持函数重载注意,Cython内部支持引用"&"与指针"*"操作,支持常量"const"限定(但const可以忽略)。
- 常见操作:
- 头部编译指令:
# cython: language_level=3 # 指定Python版本 # distutils: language=c++ # 指定C++编译
- 加载Cython模块:
from libcpp.vector cimport vector from libcpp.string cimport string
- 加载外部C++头文件及源文件:
cdef extern from '*.h': ... cdef extern from '*.cpp': pass
- 头部编译指令:
- 细节问题:
- setup.py文件中,sources参数必须保证加载到所有涉及到的C++源文件,但是不能重复加载;include_dirs参数可以附加包含目录;
- 当需要实例化一个C++接口下的类时,必须确保该类至少持有默认构造函数;
C++实例访问:
① 直接访问 $\rightarrow$ 通过实例 $\rightarrow$ 类持有默认构造函数
② 间接访问 $\rightarrow$ 通过指针 $\rightarrow$ 动态开辟空间注意内存释放(__dealloc__) - 采用cdef声明C++数据类型时需要注意:C++接口端类内部以及所有形参列表中均不能添加cdef关键字,其它地方均建议添加cdef关键字;
同时,无类型声明的对象默认为Python对象类型,可以通过Python对象类型向接口内部传入str对象,再在合适的地方转换为bytes对象; - 采用bint类型代替bool类型;
- Cython接口层级划分参考: