Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cython: How to assign a C function to a Python/ Cython variable?

At the moment I'm trying out Cython and want to see, if I can write my whole project in this language, unfortunately I have quite a problem.

I've got a C library lets call it "lib.c" from which I import a function:

cdef extern from 'lib.c':
    double compute(double params[7], double IN[2])

Now I want to assign this function to an arbitrary variable which does not have to be accessible from Python:

K = compute

which is no problem at all in Python, but on compiling I get the error

Cannot convert 'double (double *, double *)' to Python object.

Wrapping the C function with a Cython function does not work either. If e.g. I do

cdef double _K_wrap(double params[7], double IN[2]):
    return compute(params, IN)

K = _K_wrap

I get the same error.

Any suggestions of how to assign a C function to a Python/ Cython variable would be greatly appreciated. Thanks in advance!

EDIT:

OK, I just tried the suggestion of hivert:

ctypedef double (*Func)(double params[7], double IN[2])

cdef class FunctionHandler:
    cdef Func K
    def __cinit__(self, Func f):
        self.K = f
    def __call__(self, double params[7], double IN[2]):
        return self.K(params, IN)

K = FunctionHandler(compute)

This results in the same error. Probably I did something wrong in the __call__ method.

like image 249
LSchueler Avatar asked Jun 25 '26 23:06

LSchueler


1 Answers

You have to wrap your function in a cdef class:

cdef extern from 'lib.c':
    double compute(double params[7], double IN[2])

ctypedef double (*Func)(double params[7], double IN[2])

cdef class FunctionHandler:
    cdef Func K

    # def __cinit__(self, Func f):
    #    self.K = f

    def __init__(self):
        raise Exception, "FunctionHandler cannot be instanciated from Python"

    def __call__(self, list pm, list inn):
        cdef double parm[7], cin[2]
        for i in range(7):
            parm[i] = pm[i]
        for i in range(2):
            cin[i] = inn[i]
        return self.K(parm, cin)

cdef CreateFunctionHandler(Func f):
    cdef FunctionHandler res = FunctionHandler.__new__(FunctionHandler)
    res.K = f
    return res

example = CreateFunctionHandler(compute)

then

>>> import wrap
>>> wrap.example([1.1]+range(6), [4.4, 1.])
8.64
like image 171
hivert Avatar answered Jun 28 '26 11:06

hivert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!