cdef
function can be only overriden by a cdef
(or cpdef
) function in the derived class. This is also the reason, cython emits warning:
warning: xxxxx.pyx:yy:z: Overriding cdef method with def method.
for the example above.
The usual def
-function is very flexible: Not only multiple inheritances must be taken into account, but for example also monkey-patching. But that also means there is not much place for optimization: there is not much more Cython can do than using python's machinery, i.e. PyObject_GetAttr
/PyObject_GenericGetAttr
+ PyMethod_GET_SELF
+ PyMethod_GET_FUNCTION
+ call of the function.
This flexibility leads to large overhead, so cdef
-functions avoid it by using a different strategy, which is similar to C++-virtual functions:
- Every
cdef
-class has a virtual table, where the pointer to cdef-functions are stored, every one in its own slot.
- Every object of this
cdef
-class has a pointer to this virtual table thus the calls to cdef-functions can be resolved at the run time and the resolution costs only an indirection.
- A subclass can override a
cdef
-function by putting another function-pointer into the correspoding slot in the virtual table.
A typicall call of the cdef-function looks as follows:
%%cython
cdef class A:
cdef doit(self):
print(42)
def call_doit(self):
self.doit()
The self.doit()
leads to the following c-code:
((struct __pyx_vtabstruct_XXX_A*)__pyx_v_self->__pyx_vtab)->doit(__pyx_v_self, 0);
The v-table of the object __pyx_v_self
is interpreted as v-table of the cdef-class A
(even if self
is not an instance of A
but of a derived class, this operation works correctly) and slot doit
is executed.
When a class, let's say B
derives from A
it can override the slot doit
, so B's version of the doit
were called. The slot doit
is overriden by providing a corresponding definition of cdef
-function.
As one can see, there are different machineries at play when a def
function is called compared to a cdef
-function.
Thus cdef
functions are overriden only by other cdef-functions (and not def
-functions). Being more precise, one can also use a cpdef
-method for overwriting - but in your example it will not work because cpdef
functions cannot have double *
arguments, as they cannot be converted automatically by Cython to Python-objects,and the signatures of the overriding and overrided functions must match.