If you have a fused function that is exposed to Python, it also needs to be specialized from Python (in Cython space all this functionality already works). There are two ways to do this:
- directly calling
For indexing from Python space, you can use (Cython) types or strings. So if you have a function in Cython like
def f(cython.integral x, cython.floating y):
print x, y
then it can be indexed as follows:
module.f["int, long double"]
Please note that this example is for demonstration only, one could just use the largest types that are needed here.
All these index operations return a new specialized version of the function.
You can also call the function immediately, like
and the specialized version with the largest types will be called, if it can be inferred from the types of the arguments, otherwise a TypeError is raised.
In an attempt to support all this, “binding Cython functions” were also made to be a bit more like actual Python functions. Vitja has added quite a bit more than just a __dict__, and functions should then also be pickle-able.
Because these binding functions can currently only be used for Python (def and cpdef) functions and methods of normal classes (non-extensions classes), the fused version (which will be a subclass) will bind differently based on whether it’s in a normal class, or in an extension class. In a normal class the methods expect
self to be in the args tuple, or depending on the signature, as the second argument to the C function. In an extension class however, it expects code>self to be passed in as part of the
PyCFunctionObject, through the
m_self attribute (i.e.,
PyDescr_NewMethod). Unfortunately, we cannot just at binding time decide to use which, because we need to be subscriptable after binding. So we have to implement
tp_call and for extension methods bind
m_self (so for unbound calls we need to get the tail of the args tuple) and for normal methods we need to type check
args (‘self’) for unbound calls.