I want to have a Cython function in a class, and exposure a ufunc version of it to Python, while keeping the fast scaler version for use in Cython. My current attempt to do this gives me (nearly) what I want, however means I have to write 4 versions of every function I want to do this for, which feels very awkward.
Is there a better way of doing this?
Current Attempt
cdef double _func(double p, double x):
# (1) actual implementation ... pretend some math is here
return x / p
@cython.ufunc
cdef double _ufunc(double p, double x):
# (2) the ufunc 'decorator' only works outside classes so need this here
return _func(p, x)
@cython.final
cdef class Thing:
cdef readonly double p
def __cinit__(self, double p):
if p == 0: raise ValueError(f"p must not be 0")
self.p = p
cdef _func(self, x):
# (3) this version gives me the API I want in Cython
# (would prefer to have just `func`)
return _func(self.p, x)
def func(self, x):
# (4) this version gives me the API I want in Python
return _ufunc(self.p, x)
Desired Use In Python
t = Thing(p=5)
t.func(x=4)
t.func(x=np.linspace(0,1,100))
Desired Use In Cython
# class to hold (possibly many) parameter's & check then once so can skip later checks
cdef Thing t = Thing(p=5)
cdef double y = t.func(4) # want this to be as fast a possible