In two of our previous posts, we talked about Python and C functions inside Cython respectively.
There is a third kind of function, which can be declared with the cpdef keyword, it is a hybrid of def and cdef. A cpdef function combines features from both of the other kinds of functions. And approach many of their limitations. In our previous posts, we made the cdef function c_factorial available to Python by writing a def wrapper function, named wrap_c_factorial, that simply forwards its arguments on to c_factorial and returns its result. A single cpdef function gives us these two functions automatically: we get a C-only version of the function and a Python wrapper for it, both with the same name. When we call the function from Cython, we call the C-only version but when we call the function from Python, the wrapper is called. In this way, cpdef functions combine the convenience of def functions with the performance of cdef functions.
To continue with our example we discussed in previous posts, let us define a cpdef function cp_factorial to see how we can clean up the python wrapper and c_factorial function combo. So we can define that something like this one as you can see on the screen:
cdef long c_factorial(long num): if num & lt;= 1: return 1 return num * c_factorial(num - 1)
We defined a cpdef function named cp_factorial, you should be familiar with the rest of the code if you are following me from previous posts.
Our cp_factorial provides the speed of c_factorial and the Python accessibility of py_factorial, all in one place. Its performance is identical to that of wrap_c_factorial; that is, about 10 times faster than the python version of factorial function.
But a cpdef function has one limitation because it does double duty as both a Python and a C function: its arguments and return types have to be compatible with both Python and C types. Any Python object can be represented at the C level, but not all C types can be represented in Python. So, we cannot use void, C pointers, or C arrays indiscriminately as the argument types or return type of cpdef functions.
That’s it for the cpdef functions in Cython. But before closing this discussion, I think there’s an interesting thing you should keep in mind:
C and C++ support an optional inline keyword to suggest that the compiler replace the declared function with its body wherever it is called, thereby further removing call overhead. The compiler is free to ignore inline.
Cython supports the inline keyword for cdef and cpdef functions.
we simply have to place inline after the cdef or cpdef keyword like this:
cdef inline long c_factorial(long a):
Cython passes this modifier through to the generated C or C++ code.
The inline modifier, when judiciously used, can yield performance improvements, particularly for small inlined functions called deeply nested loops.