使用Cython为Python写扩展1:初识Cython
使用Cython为Python写扩展1:初识Cython
Cython使为Python写C扩展就如同写Python代码一样简单。广泛用于数学软件包,SAGE公司,作为执行快速,可扩展的运算。它提供了安全和可维护的方法通过自动生成所需代码来构建原生Python模块。
我们经常会使用Cython将C/C++实现的系统绑定到Python中,这样我们就可以使用Python来处理高级别逻辑,原生模块来处理底层代码。
关于示例
代码
版本:
- Python:3.3
- Cython:0.19
注意:如果你使用的版本不一致,可能需要对示例进行适当修改
安装Cython
我们先来安装Cython。将Cython想象成类似Bison, flex,或者GCC,它接受输入源代码并生成其他编译和链接代码:
- Fedora: yum install Cython3
- Ubuntu/Debian: apt-get install Cython3
- curl -O http://www.cython.org/release/Cython-0.19.tar.gz tar xzvf Cython-0.19.tar.gz cd Cython-0.19 sudo python3 setup.py install
- Windows http://wiki.cython.org/InstallingOnWindows .
- pip: pip3 install cython
你好中国
我们通过以下来检查cython的安装
$ cython3 --version
Cython version 0.19
hello.pyx
print("你好中国!")
这里Cython代码仅简单打印出"你好中国!"
Makefile
all:
cython3 -3 -o hello.c hello.pyx
gcc -g -O2 -fpic -c hello.c -o hello.o `python3.3-config --cflags`
gcc -g -O2 -shared -o hello.so hello.o `python3.3-config --libs`
编译链接
$ make
现在我们已经创建了hello.so模块。
使用
python3
Python 3.3.2+ (default, Feb 28 2014, 00:52:16)
[GCC 4.8.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
你好中国!
>>>
我们直接通过import导入模块
解释
Cython使用.pyx和.pxd作为文件扩展名。现在我们仅关心.pyx文件。后面,我会介绍.pxd的使用。
我们来看看Cython是如何工作的
创建你自己的模块
现在已经看到了”你好中国“模块,让我们看看如何写你自己的模块,你可以链接你自己的一些代码,稍后,我们会介绍如何包装你的代码。
执行你的C代码
Cython时Python的超集,虽然语法和关键字都可相同工作,我们也应该弄清Python和Cython区别。让我们来构建类似hello-world风格模块,但做一些其他简单事情。
mycode.c
#include <stdio.h>
int myfunc(int a, int b)
{
printf("现在我们在C代码\n");
return a + b;
}
这是我们要调用的C代码,执行简单的运算两个数之和函数。现在我们使用Python来调用它。打开文件mycode.h,定义Cython的原型。
mycode.h
#ifndef __MYCODE_H__
#define __MYCODE_H__
extern int myfunc(int, int);
#endif //__MYCODE_H__
我们需要这样让Cython可以知道需要调用的函数原型。在实际中,你可能已经在项目头文件中定义了原型。新建mycodecpy.pyx,写入如下代码:
cdef extern from "mycode.h":
cdef int myfunc(int, int)
def callCfunc():
print(myfunc(1, 2))
在Cython代码里,我们定义了我们想使用的C代码,cdef关键字标识要链接的C代码。现在我们已经定义了所要使用的头文件,我会详细说明Python如何调用原生代码,由于直接调用C代码时危险的。所以,Cython为我们处理所有类型转换问题。基本函数包装,callCfunc,调用myfunc函数并且传递整型,然后简单打印结果。
用以下命令编译:
$ cython3 mycodecpy.pyx
$ gcc -g -O2 -fpic -c mycode.c -o mycode.o
$ gcc -g -O2 -fpic -c mycodecpy.c -o mycodecpy.o `python3.3-config --cflags`
$ gcc -shared -o mycodecpy.so mycode.o mycodecpy.o `python3.3-config --libs`
我们要链接mycode.c代码。将所有C文件编译为对象文件,然后将所有对象文件链接成一个二进制文件。因此,所以确保你链接了所有需要对象文件。
$ python3
>>> from mycodecpy import callCfunc
>>> callCfunc()
现在我们在C代码
3
所以,我们现在已经编译并且通过Python代码来调用我们原生代码。你卡亚开始绑定一些其他一些原生模块了。
类型转换
你也许注意到了我们调用直接调用Cython函数而没带参数,如果我们想带参数呢?
def callCfunc(int x, int y):
print(myfunc(x, y))
现在我们增加了两个int参数到我们定义的Python包装函数中。这里需要Python代码类型安全的转换PyObjects为C类型。当你创建一个Python整型对象。该类型不是integer而是PyObject。如果你想在C中使用,你需要通过Python C API来获取该值,但是Cython自动给你做了该事情。例如,如果你传递了不合法参数,你将会得到:
>>> callCfunc(1, ‘string‘)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "mycodecpy.pyx", line 4, in mycodecpy.callCfunc (mycodecpy.c:687)
def callCfunc(int x, int y):
TypeError: an integer is required
添加更多类型安全对象,你发现会提高速度,代码也会更漂亮。因为Cython编译器可以更加优化代码避免使用Python调用。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。