一、简介
Cython是一种包含 C 数据类型的 类似Python的编程语言,Cython 的编译器会转化 Python 代码为 C 代码,这些 C 代码均可以调用 Python/C 的 API。既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。几乎所有 Python 代码都是合法的 Cython 代码,后缀为.pyx。
二、Cython 的基础
2.1 Cython 简单编译
用hello world为例,编写文件 helloworld.pyx
:
cdef extern from"stdio.h":
extern int printf(const char *format, ...)
def SayHello():
printf("hello,world\n")
return 0
创建 setup.py
,它是一个类似 Python Makefile 的文件,用于编译.pyx。
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
setup(
name='hellocython',
ext_modules=cythonize([
Extension("hellocython", ["hellocython.pyx"]),
]),
)
命令行输入如下命令来编译你的 Cython 文件:
python setup.py build_ext --inplace
运行完上述命令会在你的当前目录生成一个新文件,如果你的系统是 Unix,文件名为 helloworld.so
,如果你的系统是 Windows,文件名为 helloworld.pyd
。
现在我们创建一个测试脚本test.py
,测试.pyd文件是否可以import:打开 Python 的解释器(interpreter),像 import 普通文件一样直接 import 你刚生成的文件:
import hellocython
hellocython.SayHello()
如果上述导入失败可以在前面加入:
import sys
sys.path.append("pathof hellocython.pyd")
上述过程我们使用setup.py
将.pyx
编译为.pyd
导入python使用。
2.2 pyximport
如果你的模块不需要额外的 C 库活特殊的构件安装,那你可以在 import 时,直接使用pyximport 模块来读取 .pyx 文件,而不需要编写 setup.py
文件。 它随同 Cython 一并发布和安装,test.py中你可以这样使用它:
import pyximport; pyximport.install()
import helloworld
它允许你在所有 Python import 的 .pyx 和 .py 模块上自动运行 Cython,包括哪些标准库和第三方库。但是,任然有不少 Python 模块 Cython 无法编译,遇到这种情况 import 机制(mechanism)会退回去读取 Python 原模块。.py 的 import 机制可按如下方式安装:
pyximport.install(pyimport = True)
三、Cython基本语法
3.1 python文件中如何调用c的文件的函数
通过Cython作为中介:
.h/.c -> .pyx -> .pyd ->.py
如现有一个sub_core.h
文件和sub_core.c
文件:
//sub_core.h 声明
int sub(int a,int b);
//sub_core.c 实现
#include"sub_core.h"
int sub(int a,int b){
return a-b;
}
如果我们想要在test.py
中调用上面c文件的sub()函数,和刚刚一样,我们需要使用cython语言,编写sub.pyx
文件来导入c文件:
# 将.h文件的函数导入.pyx文件
cdef extern from "sub_core.h"
int sub(int a,int b)
# 在.pyx文件中直接使用.c文件里的函数
def sub_with_c(a,b):
return sub(a,b)
接下来使用sutup.py
对.pyx文件进行编译,生成wrapper_sub.pyd
文件:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
# 这个name就是编译生成的.pyd文件名,sources导入.pyx和.c文件
ext=Extension(name=“wrapper_sub”,sources=["sub.pyx","sub_core.c"])
setup( ext_modules=cythonize(ext) )
最后在test.py
文件中,就可以调用用c定义的sub()函数啦:
# 导入wrapper_sub.pyd文件
import wrapper_sub
print(sub(4,2))
>>2
3.2 基础语法
变量:
cdef c的数据类型 变量名
指针:
cdef int a=10
cdef int * p = &a # 定义指针
x = p[0] # 使用[0]解引用,而非*,因为python中*用于抓包
print(x)
>>10
cdef,cpdef,defq创建函数的区别:
cdef 不能被外部.py调用
def 可以被外部.py调用,是python和cython的桥梁
cpdef 是cdef和cef的桥梁