原文地址:http://gashero.iteye.com/blog/649516

Cython应用手记

作者:日期:

gashero
2010-03-29

目录

  • 1   简介
  • 2   基本使用
  • 3   调用其他C库
    • 3.1   简单例子
    • 3.2   重新定义外部C库的定义
  • 4   类定义
  • 5   与Python交互

1   简介

一种为Python写C扩展的方式,尝试一下。

参考文献:

  1. [r] 官方主页: http://www.cython.org/
  2. [r] Cython三分钟入门: http://blog.csdn.net/lanphaday/archive/2009/09/17/4561611.aspx
  3. [u] A quick Cython introduction: http://www.perrygeo.net/wordpress/?p=116 其实就是上文的原文
  4. [i] Cython's Documentation: http://docs.cython.org/ 看到"Extensioin types"

2   基本使用

Cython基于pyrex,但是拥有更多功能和优化。用来写Python的C扩展的,并生成有效的C代码。写出的文件扩展名是 ".pyx" ,已经可以算作一种语言了。

一个简单的加法函数( addtest.pyx ):

def addtest(a,b):cdef float c=a+breturn 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代码的方式:

  1. 使用 setup.py ,常用
  2. 使用pyximport导入 ".pyx" 文件
  3. 运行cython命令编译出.c文件后再编译成.so文件
  4. 使用Sage

使用 setup.py 方式,例如一个 hello.pyx 文件,编写的 setup.py 如下:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_extext_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 retret=x**2-xreturn 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_extext_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:passctypedef void* QueueValueQueue* 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_exccdef class Queue:cdef cqueue.Queue_c_queuedef __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方法。

Cython应用手记相关推荐

  1. 编译ceph源码:cython module not found问题的解决

    环境:centos7.5 ceph版本:12.2.1 在当前环境对ceph源码rpm包进行重新编译 执行命令rpmbuild --rebuild ceph-12.2.1-0.el7.src.rpm 最 ...

  2. AM335X的汇编语言与c语言,X86汇编语言学习手记 -- 汇编和C协同

    X86汇编语言学习手记(3) 2004年12月 在X86汇编语言学习手记(1)(2)中,可以看到栈(Stack)作为进程执行过程中数据的临时存储区域,通常包含如下几类数据: 局部变量 函数调用的返回地 ...

  3. 结巴分词和自然语言处理HanLP处理手记

    手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...

  4. 大叔手记(17):大叔2011年读过的书及2012年即将要读的书

    前言 2011年是大叔最累的一年(基本上都是晚上12点以后睡觉,早上6点30分起),读得书也是异常的多,一方面要保持自己的技术在最前列,另外方面技术管理和项目管理方面的东西也要进一步进阶,2011年读 ...

  5. cython安装、使用

    cython安装.使用 原创 2012年09月27日 17:25:11 8436 0 0 一.cython 在linux(ubuntu)下安装 sudo apt-get install cython ...

  6. webpack入门学习手记(一)

    本人微信公众号:前端修炼之路,欢迎关注. 之前用过gulp.grunt,但是一直没有学习过webpack.这两天刚好有时间,学习了下webpack.webpack要想深入研究,配置的东西比较多,网上的 ...

  7. python如何调用c++numpy.ndarray代码_python – 在cython中使用numpy:定义ndarray数据类型/ ndims...

    我正在尝试编写一些cython代码来进行numpy数组的计算. Cython似乎不喜欢我见过的所有示例中使用的[]来定义数据类型和维数. 例如,我有一个文件test.pyx: cimport nump ...

  8. python转cython_用Cython加速Python到“起飞”(推荐)

    事先声明,标题没有把"Python"错打成"Cython",因为要讲的就是名为"Cython"的东西. Cython是让Python脚本支持 ...

  9. 【手记】解决启动SQL Server Management Studio 17时报Cannot find one or more components...的问题

    [手记]解决启动SQL Server Management Studio 17时报Cannot find one or more components...的问题 参考文章: (1)[手记]解决启动S ...

  10. ELK菜鸟手记 (三) - X-Pack权限控制之给Kibana加上登录控制以及index_not_found_exception问题解决

    ELK菜鸟手记 (三) - X-Pack权限控制之给Kibana加上登录控制以及index_not_found_exception问题解决 参考文章: (1)ELK菜鸟手记 (三) - X-Pack权 ...

最新文章

  1. seaJs api 帮助文档
  2. 安装phpMyAdmin图文教程
  3. 基于Lucene查询原理分析Elasticsearch的性能
  4. 【Matlab 控制】多智能体一致性收敛仿真
  5. leetcode 205. 同构字符串
  6. java四神兽_SpringCloud五大神兽之Eureka
  7. C 语言,你真的懂递归了吗?
  8. Spring Boot EasyUI datagrid
  9. ikun 潜入?疑似 B 站后台源码泄露
  10. 谷歌最新开源的工具可以自动化查找并修复 bug!
  11. OUTLOOK邮箱设置
  12. echarts常用方法(一)
  13. Linux TUN/TAP 虚拟网卡编程入门https://backreference.org/2010/03/26/tuntap-interface-tutorial/...
  14. 现代软件工程_团队项目_阿尔法阶段_第二次会议记录_2017.11.13
  15. java字符串时间去掉秒_Java:当秒和毫秒均为0时,DateTimeFormatter无法解析时间字符串吗?...
  16. c语言逻辑运算符的作用,C语言逻辑运算符知识整理
  17. Mac部署Prometheus + Grafana监控
  18. VR Masterclass
  19. 解决maven库中没有Oracle jdbc驱动的问题Cannot resolve com.oracle:ojdbc14:10.2.0.1.0
  20. 被mysql虐待的一天

热门文章

  1. GPO 安装 .net 4.5和WMF4
  2. 监控apache脚本原理
  3. 洛谷 P1827 美国血统 American Heritage Label:字符串Water
  4. 1.1浅谈Spring(一个叫春的框架)
  5. 程序设计实习MOOC / 程序设计与算法(二)第二周测验(2018春季)
  6. 12306微信小程序上线 提供余票查询暂不支持购票
  7. 这些 iOS 面试基础题目,你都深入了解吗?
  8. windows进程中的内存结构
  9. 单应性(同义词直射变换、射影变换和射影性等)(来自wiki)
  10. python request保持连接_python接口自动化 - Requests-3 高级用法