Passing Input/Output to/from functions in Cython

2019-08-03 07:23发布

问题:

I am trying to write a function in cython which should receive a list argument from python manipulate it in some way by generating a 2D array of it in C/C++ and then return it to python as a 2D list. I simplified the code to ask my question:

I expect c_Func to do the procedure which I can compile it without error. The second function is the callable function but obviously it doesn't work. First I have to deal with the problem that a list cannot be replaced by a double* and second it the problem that py_Func can't return a double*. So how should I change these two?

cdef double** c_Func(int dim,double* init_val):
    cdef double** frozen_ans= <double**> malloc(dim*sizeof(double))
    frozen_ans[0]=init_val
    return frozen_ans
def py_Func(int dim, double* init_val):
    return c_Func(dim,init_val)

回答1:

I assume that you want to manipulate the data from C/C++.

Do not use malloc, as you're not going to be able to free that pointer later, and your code will leak memory. Use instead a container that can be handled later by python, like a numpy array for example.

With 'handle' I mean the fact that when the numpy array ends up in the python garbage collector, python will deallocate that memory block for you.

Expanding on the numpy option, you can create a contiguous, c-style numpy array arr from within cython, fill it/use it as a c array from pure c code using its address &arr[0] (as long as it's not empty), and then return it as a python numpy.ndarray object. See this on numpy objects convenient access. This has the strong advantage that arr and can be treated as a c array from c code.

At the end of your cython function, if you don't want to return a numpy array, you can use arr.tolist() method, but this will incur in a overhead, because you are creating a new list.

Regarding the input part, you say your function must accept a python list. It could either:

  • accept a numpy array, manipulate it and return it.
  • accept a python list l, cast it to a numpy array with np.ascontiguousarray(l), manipulate it and return it. In this case you're incurring in a copy overhead, but there's little you can about it.


标签: python cython