【python开发技术】Cython 开发学习之def, cdef, cpdef

Cython 开发学习之def, cdef, cpdef

Posted by ZhangPY on April 9, 2020

【python开发技术】Cython 开发学习之def, cdef, cpdef

由于Cython是基于C运行时,因此,允许使用cdef和cpdef。

这个三个东西的使用有点乱七八糟,下面梳理一下。

关键的不同在于这些function可以在哪里面进行调用

def可以从Python,Cython中调用,而cdef可以被Cython和C中调用。都可以用混合 typed and untyped 变量进行声明,这两种情况内部都会被Cython编译为C,被编译的代码应该会非常相像。

# A Cython class for illustrative purposes
cdef class C:
   pass

def f(int arg1, C arg2, arg3):
    # takes an integer, a "C" and an untyped generic python object
    pass

cdef g(int arg1, C arg2, arg3):
    pass

这例子中,f对python可见,g不能被python调用,g将会翻译成C signature: PyObject* some_name(int, struct __pyx_obj_11name_of_module_C *, PyObject*),这样g就可以当做函数指针被传递给C的函数,而f则不能直接被C调用。

cdef 的一些限制

cdef不能在别的函数中被定义,这是因为在C的函数指针中无法存储任何捕获的变量,下面的例子就是非法的:

# WON'T WORK!
def g(a):
   cdef (int b):
      return a+b

cdef函数不能接受*args, **kwargs类型的变量,因为它们不容易被翻译为C标签。

cdef的好处

cdef可以使用任何类型的变量,包括 int* a等。而def不能这么定义。

cdef可以声明返回值类型,如果没有被声明,默认返回PyObject* in C。而def总是返回一个Python对象,所以不能声明返回值。

cdef int h(int* a):
    # specify a return type and take a non-Python compatible argument
    return a[0]

cdef比def更快,因为它被翻译为简单的C函数调用。

cpdef的函数

cpdef会让Cython生成一个cdef函数(允许一个从Cython中来的快速的函数调用)和一个def函数(允许从python进行调用)。而在内部这个def函数是直接调用了cdef的函数。所以,变量类型限制是cdef和def两者的交集。

什么时候使用cdef函数?

当函数被调用后,这cdef和def两者内部的速度是没有差别的。因此,在下列情况再用cdef:

  • 需要传递non-Python类型 in or out
  • 需要作为函数指针传递给C
  • 经常调用,加速该函数调用很重要,而不需要从python中调用。

2020-04-09