2 基
本使用
Cython基于pyrex,但是拥有更多功能和优化。用来写Python的C扩展的,并生成有效的C代码。写出的文件扩展名是 ".pyx"
,已经可以算作一种语言了。
一个简单的加法函数( addtest.pyx
):
def addtest(a,b):
cdef float c=a+b
return c
编译和生成动态库:
cython addtest.pyx
gcc -c -fPIC -I/usr/include/python2.5 addtest.c
gcc -shared addtest.o -o addtest.so
使用:
$ python
>>> import addtest
>>> addtest(1,2)
3.0
构建Cython代码的方式:
- 使用 setup.py
,常用
- 使用pyximport导入 ".pyx" 文件
- 运行cython命令编译出.c文件后再编译成.so文件
- 使用Sage
使用 setup.py
方式,例如一个 hello.pyx
文件,编写的 setup.py
如下:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules=[Extension('hello',['hello.pyx'])]
setup(
name='Hello world app',
cmdclass={'build_ext':build_ext},
ext_modules=ext_modules
)
构建使用命令 python
setup.py
build_ext
--inplace
。
Cython提高速度的主要原因是使用静态类型。可以在任何参数前直接使用C的类型定义。函数内的话要加"cdef"前缀。如:
def f(double x):
cdef double ret
ret=x**2-x
return ret
仅仅使用Cython编译纯Python代码可以提高35%的性能,几乎全部使用静态类型以后提高4倍。
C风格函数声明,"except? -2"表示返回-2时就是出错了。不过"except *"是肯定安全的。如:
cdef double f(double) except? -2:
return x**2-x
使用cpdef时,这个函数就可以同时被C和Python调用了。当使用了C函数时,因为避开了昂贵的函数调用,旺旺可以提高150倍的速度。
不要过度优化,一步步的优化并且查看profile。使用"cython -a"参数可以查看HTML报告。
3 调
用其他C库
3.1 简
单例子
导入"math.h"中的 sin()
函数并使用:
cdef extern from "math.h":
double sin(double)
cdef double f(double x):
return sin(x*x)
Cython不会去扫描头文件,所以自己必须再声明一遍。下面是使用时必须连接上其他库的 setup.py
文件:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules=[
Extension('demo',['demo.pyx',],libraries=['m',])
]
setup(
name='Demos',
cmdclass={'build_ext':build_ext},
ext_modules=ext_modules,
)
同理可以使用任何动态或静态编译的库。
3.2 重
新定义外部C库的定义
一段C代码,头文件中的类型定义与函数声明:
typedef struct _Queue Queue;
typedef void *QueueValue;
Queue *queue_new(void);
void queue_free(Queue *queue);
int queue_push_head(Queue *queue, QueueValue data);
QueueValue queue_pop_head(Queue *queue);
QueueValue queue_peek_head(Queue *queue);
int queue_push_tail(Queue *queue, QueueValue data);
QueueValue queue_pop_tail(Queue *queue);
QueueValue queue_peek_tail(Queue *queue);
int queue_is_empty(Queue *queue);
对应的Cython定义,写入一个".pxd"文件中:
cdef extern from "libcalg/queue.h":
ctypedef struct Queue:
pass
ctypedef void* QueueValue
Queue* new_queue()
void queue_free(Queue* queue)
int queue_push_head(Queue* queue, QueueValue data)
QueueValue queue_pop_head(Queue* queue)
QueueValue queue_peek_head(Queue* queue)
int queue_push_tail(Queue* queue, QueueValue data)
QueueValue queue_pop_tail(Queue* queue)
QueueValue queue_peek_tail(Queue* queue)
bint queue_is_empty(Queue* queue)
大部分时候这种声明与头文件几乎是一样的,你可以直接拷贝过来。唯一的区别在最后一行,C函数的返回值其实是布尔值,所以用bint类型会转换成
Python的布尔值。
这里可以不关心结构体的内容,而只是用它的名字。
4 类
定义
一个类的例子:
cimport cqueue
cimport python_exc
cdef class Queue:
cdef cqueue.Queue_c_queue
def __cinit__(self):
self._c_queue=cqueue.new_queue()
这里的构造函数是 __cinit__()
而不是 __init__()
。虽然 __init__()
依然有效,但是并不确保一定会运行(比如子类忘了调用基类的构造函数)。因为未初始化的指针经常导致Python挂掉而没有任何提示,所以 __cinit__()
总是会在初始化时调用。不过其被调用时,对象尚未构造完成,所以除了cdef字段以外,避免其他操作。如果要给 __cinit__()
构造和函数加参数,必须与 __init__()
的匹配。
构造函数初始化资源时记得看看返回的资源是否是有效的。如果无效可以抛出错误。Cython提供了内存不足异常,如下:
def __cinit__(self):
self._c_queue=cqueue.new_queue()
if self._c_queue is NULL:
python_exc.PyErr_NoMemory()
Cython提供的析构函数,仅在建立成功内部对象时释放内部对象:
def __dealloc__(self):
if self._c_queue is not NULL:
cqueue.queue_free(self._c_queue)
将数据以通用指针方式进入,和返回时的强制类型转换:
cdef append(self,int value):
cqueue.queue_push_tail(self._c_queue,<void*>value)
cdef int pop(self):
return <int>cqueue.queue_pop_head(self._c_queue)
Cython除了支持普通Python类以外,还支持扩展类型,使用"cdef
class"定义。在内存占用和效率上更好。因为使用C结构体存储字段和方法,而不是Python字典。所以可以存储任意C字段类型,而不是其
Python包装。访问时也是直接访问C的值,而不是通过字典查找。
普通的Python类可以继承自cdef类,但是反之则不行。Cython需要知道完整的继承层次来定义C结构体,并且严格限制单继承。不过普通
Python类可以继承任一数量的Python类和扩展类型,无论在Python中还是在Cython代码中。
5 与
Python交互
如果Cython调用Python函数失败,则直接返回NULL,而不是异常对象。
如果一个函数既有可能返回NULL,也有可能返回0,则处理起来就比较麻烦。Python C API的做法是 PyErr_Occurred()
函数。不过这种方式有性能损耗。在Cython中你可以自己指定哪个返回值代表错误,所以环境只要检查这个返回值即可。其他所有值都回无损耗的被接受。
在函数定义时指定except子句,则仅在函数返回该值时检查是否需要抛出异常。这样同一个函数返回0和返回0同时返回错误就可以区分开。例子:
cdef int pop(self) except? 0:
#...
类中的 cdef 定义C方法,而 cpdef 可以同时定义C方法和Python方法。
相关推荐
[Packt Publishing] Cython 编程学习教程 (英文版) [Packt Publishing] Learning Cython Programming (E-Book) ☆ 图书概要:☆ Expand your existing legacy applications in C using Python Overview Extend ...
It’s possible with Cython, the compiler and hybrid programming language used by foundational packages such as NumPy, and prominent in projects including Pandas, h5py, and scikits-learn. In this ...
Cython封装Callback函数文章 示例 http://blog.csdn.net/i2cbus/article/details/18415333
Cython: A Guide for Python Programmers covers all you need to know about the eponymous creole programming language and Python-to-C compiler. If you have heard of Cython and want to find out more, or ...
参考Cython官方文档编写而来的一个Cython封装C++的示例demo,可入门学习。
此为适用于linux系统python3.6的cython安装包,版本为0.29
由python、C、Cython实现的二叉树树源码。树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。树结构在客观世界中广泛存在,如人类社会的...
cython_bbox-0.1.3 未修改pip源码
Learning Cython Programming
python库。 资源全名:Cython-0.29.3.tar.gz
Python第三方包 Cython
引言 通常,在 Python 中写循环(特别是多重循环)非常的慢,在文章 //www.jb51.net/article/133807.htm中,我们的...cimport cython DTYPE = np.float ctypedef np.float_t DTYPE_t def update_state(np.ndarray[DTYP
Cython-0.29.30-py3-none-any.whl
OrderedDict的Cython实现
详细介绍了Cython文件在window与linux下的编译,以实际例子说明。
Cython是一个编程语言,它通过类似Python的语法来编写C扩展并可以被Python调用.既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。译出最终的Python可调用的模块。
《Cython入门》 示例 http://blog.csdn.net/i2cbus/article/details/18181637
Cython-0.23.3.tar.gz : Cython-0.23.3安装包
最近的MOT杀出了一匹黑马[FairMOT](https://zhuanlan.zhihu.com/p/131430303),于是我心痒难耐想拿来试试,我是在自己笔记本上跑的,但是安装环境的时候cython-bbox一直安装报错,作为一只初级菜鸟只能到处找博客...