文章目录
- 1. 数据类型声明
- 1.1 Cython里定义一个C变量
- 1.2 使用C语言中 struct,union或enum类型
- 1.3 cython声明变量与初始化
- 2. 类型转换、预编译、for循环
- 3. python-C-cython 变量对应关系
- 4. jupyter notebook 调试
- 5 其它
在官方文档中说的很明白,所有的python代码都是合法的cython代码。以下变量声明不再赘叙。
开发环境:jupyter notebook
开启 Cython 运行环境:%load_ext Cython
1. 数据类型声明
1.1 Cython里定义一个C变量
在Cython里定义一个C变量和C语言类似,不同的地方就是在声明的最前面要加上cdef,另外,末尾不用加分号";
%load_ext Cython
cdef int an[10] # 声明数组,数组大小:10
cdef int n = 123 # 声明同时初始化
cdef int *pn = &n
print("%d ",pn[0])
cdef int i, j, k # 声明整型:i,j,k
cdef float f, *h # 声明浮点型f,指针h
注意:以Cython里不能用类似*ptr这样代码来对指针变量进行取值,而必须用ptr[0]这样的形式,如上面的例子中,printf("%d\n",*pn)是编译通不过的。(在C语言中,*ptr与ptr[0]都是指针访问方式)
1.2 使用C语言中 struct,union或enum类型
简单的声明
%%cython --a
cdef struct Grail:
int age
float volume
cdef union Food:
char *spam
float *eggs
cdef enum CheeseType:
cheddar, edam,
camembert
cdef enum CheeseState:
hard = 1
soft = 2
runny = 3
enum 枚举类型
显然Cython支持C语言的指针与取址运算符。输出的是一个字典形式
cdef struct AB:
int a
int b
def StructTest():
cdef AB ab
ab.a = 1
ab.b = 2
return ab
>>> import test
>>> test.StructTest()
{'a': 1, 'b': 2}
=========================================================
cdef struct AB:
int a
int b
def StructTest():
cdef AB ab
cdef AB *pAB = &ab
pAB.a = 1
pAB.b = 2
return pAB[0]
>>> import test
>>> test.StructTest()
{'a': 1, 'b': 2}
关于结构体,一般用于结构体数组中,
1.3 cython声明变量与初始化
Python类型list
,dict
,tuple
的定义与初始化。使用结构类型声明变量。
cdef int x,y,z # 整型
cdef char *s # 字节
cdef str name # 字符串
cdef float x = 0.1 # 单精度 浮点型
cdef double x = 0.1 # 双精度 浮点型
cdef list list_num = [] # list 定义并初始化列表
cdef dict abc_dict # dict 字典
cdef tuple tuple1 # 元组
cdef object objec1t # 任意对象
cdef list cast_list = <list?>a # 安全定义传入列表数据,a为传入的列表数据
cdef (double, int) bar # 它们可以编译为 C结构,并且可以用作Python元组的有效替代方案。
cdef uint64_t binN # binN:8字节整型 (拓展:uint8_t的最大数=256)
cdef np.ndarray[np.uint64_t, ndim=2] images_array1 # images_array:多维数组
cdef np.ndarray[np.float32_t, ndim=2] images_array2
cdef int[:, :] array_view = array_1 # 声明整数的memoryview
cdef int[:, ::1] result_view = result_1 # 声明整数的连续化memoryview
=============================================================================
ctypedef struct mycpx: # 定义结构类型
float real
float imag
ctypedef union uu: # 定义联合类型
int a
short b, c
cdef mycpx zz
====== 初始化:=======
cdef mycpx a = mycpx(3.1415, -1.0)
cdef mycpx b = mycpx(real=2.718, imag=1.618034)
cdef mycpx zz
zz.real = 3.1415
zz.imag = -1.0
cdef mycpx zz = {'real': 3.1415, 'imag': -1.0} # 这个是我们常用的方式
也可以使用拓展类型定义:https://cython.readthedocs.io/en/latest/src/userguide/extension_types.html#extension-types uint8_t / uint64_t 详情
2. 类型转换、预编译、for循环
在Cython里用<>
替代了()来进行类型转换,如:
cdef float a= 123.456
cdef int b
b = <int>a
=====================
cdef int n
a = 'hello,world'
n = <int>a
注意的是:n =<int>a
把一个Python字符串对象指针强制转换成了一个整形变量,这在封装回调函数时经常会用到强制将一个Python对象指针强制转换成C类型的情况。
更多请查看:https://cython.readthedocs.io/en/latest/
Cython预编译
Cython有一个DEF关键字创建宏,是一个编译时符号,类似于C语言的#define,DEF常数必须在编译时被解析,而且只能是简单类型,它们可以是浮点数、整数或者字符串,如下:
DEF E = 2.718281828459045
DEF PI = 3.141592653589793
def feynmans_jewel():
return E ** (1j * PI) + 1.0
for循环
cdef unsigned int i, n = len(a) - 1
for i in range(1, n):
a[i] = (a[i-1] + a[i] + a[i+1]) / 3.0
cdef int y, half_S=0, height=50, S = 2 # 步长不为1 时
for y from half_S <= y < height by S:
3. python-C-cython 变量对应关系
python | C/C++ | cython |
a=True | bool a=1/True | cdef/cpdef bint a=1 |
a=”2” | char* a=’2’ | cdef/cpdef char* a=’2’ |
a=”2123bc” | char* a=”2123bc” | cdef/cpdef char* a=”2123bc” |
a=2 | int a=2 | cdef/cpdef int a=2 |
a=2 | short int a=2 | cdef/cpdef short int a=2 |
a=2.0 | double a=2.0 | cdef/cpdef double a=2.0 |
a=2.0 | float a=2.0 | cdef/cpdef float a=2.0 |
a=np.zeros(10) | double[] a=np.zeros(10) | cdef/cpdef double[:] a=np.zeros(10) |
a=np.zeros(10,10) | double[,] a=np.zeros(10,10) | cdef/cpdef double[:,:] a=np.zeros(10,10) |
4. jupyter notebook 调试
%load_ext Cython
%%cython --annotate
cdef int a = 0
for i in range(10):
a += i
print(a)
各位可以试一下。
5 其它
- github网址:https://github.com/cython
- Cython官网使用文档:https://cython.readthedocs.io/en/latest/
- cython加速关于循环的运算
关于循环加速:https://stackoverflow.com/questions/40451203/cython-parallel-loop-problems - Cython的C++库:https://github.com/cython/cython/tree/master/Cython/Includes/libcpp
Cython中C++泛型算法的使用:https://github.com/cython/cython/blob/master/Cython/Includes/libcpp/algorithm.pxd
案例:https://github.com/cython/cython/commit/05059e2a9b89bf6738a7750b905057e5b1e3fe2e - python3中关于cython的使用(将函数指针转换为可调用对象):https://python3-cookbook.readthedocs.io/zh_CN/latest/c15/p12_turning_function_pointer_into_callable.html
- 使用感想
我们用cython,都是想用C的循环来替换python的循环,以此来加速。
在使用cython中,我们所作最多的是数据类型的申明与转换。
在定义cython的cdef函数中,我们希望with nogil的运行代码,所有整个函数不要有python对象,numpy对象以及对象的返回。
若是使用已知数组,尽量申明并初始化C数组或者cython数组等轻量级数组。注意:C语言必须指明数组长度个数。也就是是个定量。
编译命令:python setup.py build_ext --inplace
特别鸣谢:
https://cython.readthedocs.io/en/latest/src/userguide/numpy_tutorial.html
https://hatboy.github.io/archives/page/4/
类:https://hatboy.github.io/2017/08/10/%E7%AC%AC%E4%BA%94%E7%AB%A0-Cython%E5%92%8C%E6%89%A9%E5%B1%95%E7%B1%BB%E5%9E%8B/