The classic C solution to this type of
problem is to use a void* as an argument to your function pointer
to capture the arguments. It'd typically point to some struct
specific to the function. For example
cdef struct add_value_struct:
int value
cdef int add_value(int x, void* s)
nogil:
cdef add_value_struct* s_cast = <add_value_struct*>s
return x+s_cast.value
cdef some_nogil_function(int (*func)(int, void*) nogil, void*
closure) nogil:
return func(10, closure)
cdef add_value_struct s = {'value': 5}
some_nogil_function(add_value, <void*>(&s))
Alternatively you might be able to use inheritance and cdef
classes (instead of fused types):
cdef class Base:
cdef int call(self, int x) nogil:
return 0 # dummy implementation
cdef class Impl1(Base):
cdef int value
cdef int call(self, int x) nogil:
return x+self.value
cdef class Impl2(Base):
...
cdef some_nogil_function(Base f) nogil:
return f.call(10)
You may run into the problem that you're a bit restricted in what
you can do in cdef classes without the GIL - they are ultimately
Python objects so anything that causes reference counting will
need to GIL for example. But something like that should work.
However, it's sometimes a choice
between Python-level convenience and C-level speed. You can't
always have both (easily)