使用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调用。

使用Cython为Python写扩展1:初识Cython,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。