本文主要介绍Cython支持的三种函数定义的方式,def,cdef以及cpdef
以求两数的和为例
# 接收Python对象作为输入,返回Python对象
# 可以像Python中函数那样使用
def sum_(a, b):
return a + b
# 如果是如下情形,这也是个Python函数,首先把传入的Python类型的a,b转成C类型,然后相加,再把结果转成Python类型返回
def sum_(int a, int b):
return a + b
// 参数类型和返回值类型都被静态声明了,都为C类型
// cdef定义的函数不允许从定义的模块外部调用
// 如果cdef没有指定返回值类型,返回相应的Python类型
cdef long sum_(long a, long b):
return a + b
// 如果希望能够实现外部的调用,可以使用Python函数对其进行封装
def wrapper(a, b):
return sum_(a, b)
# cpdef : cdef 和 def的混合
# 解决了上述的外部调用的问题,无需显式的对sum_进行封装
cpdef long sum_(long a, long b):
return a + b
# 作用相当于
cdef long sum_(long a, long b): # (1)
return a + b
def sum_(a, b): # (2)
return sum_(a, b)
如果我们用Cython调用sum_,就是调用C版本的sum_,就是(1),如果用Python调用,就相当于调用了Python封装版本的sum_,就是(2)。
所以也可以看出,因为cpdef的特点,它定义的函数的参数和返回值必须既可以是Python类型的也可以是C类型的,所以像在C中的指针类型等就无法作为这类函数的参数了。
接下来还有一个问题就是异常的处理
对于一个pure Python的版本来说,除法分母为0,会产生ZeroDivisionError
可是对于cdef或者cpdef,虽然会出现ZeroDivisionError,但是仍然会返回0
为了正确的处理这个异常,Cython提供了一种语法来解决这个问题
# cpdef也一样
# 如果except后面的数字是可能作为正确的返回值出现的,就需要加?
# 如果except后面的数字的出现肯定能够说明有错误,就不需要加?
cdef int divide_(int x, int y) except -1
cdef int divide_(int x, int y) except? 0
参考资料
https://github.com/kwmsmith/scipy-2017-cython-tutorial/blob/master/04-functions.ipynb
《Cython-A Guide For Python Programmers》Chapter3 Cython in Depth