How to convert python array to cython array?

后端 未结 5 813
失恋的感觉
失恋的感觉 2020-12-17 22:14

I have an array of float values that is created in regular Python, that I want to pass to a cython function that fronts for an underlying C function. The C function requires

相关标签:
5条回答
  • 2020-12-17 22:29

    I believe you can do this by iterating over the python list of floats and putting them in a C array.

    cimport cython
    from libc.stdlib cimport malloc, free
    
    cdef:
        float * cfloats
        int i
    
    cfloats = <float *> malloc(len(pyfloats)*cython.sizeof(float))
    if cfloats is NULL:
      raise MemoryError()
    for i in xrange(len(pyfloats)):
      cfloats[i] = pyfloats[i]
    setOverlays(cfloats)
    free(cfloats)
    
    0 讨论(0)
  • 2020-12-17 22:31

    I found the Cython specific way:

    cdef float* cVerts = []
        for i in xrange(len(verts)):
            cVerts[i] = verts[i]
    setOverlays(cVerts)
    

    Interestingly enough the above two solutions were rejected by the cython compiler.

    0 讨论(0)
  • 2020-12-17 22:33

    The accepted answer is wrong and leads to a segmentation fault, because the memory for the float * is never allocated.

    The answer of @JAB shows the way to go, but I would like to elaborate more.

    Passing an array:

    The question is how to convert python array to an c-style array. Python array (from the array module) is a wrapper around continuous memory, so there is no need to copy the memory - we just can pass the pointer to the c-function:

    from cpython cimport array
    import array
    
    def set_overlays(array.array verts):
        setOverlays(verts.data.as_floats)
    

    Using array module is better than numpy because it is part of the standard library - there is no need to install something. This solution is short and nice, but has a problem: somebody could use it with an int-array and there will be no error - the memory just gets reinterpreted. Sometimes it is what one wants, but most of the time this is not the case.

    To make sure, that the passed array-object has the right type of data, memory views can be used:

    from cpython cimport array #still needed
    
    def set_overlays_memview(float[::1] verts):
        setOverlays(&verts[0])
    

    [::1] ensures, that the memory view wraps around continuous memory. However, this code has a problem if there are no elements in the memory view,because of the out-of-bounds-access verts[0]. The right way to handle it depends on the function setOverlays and is not a part of this answer.

    Passing a list:

    If we have to pass a python list to the c-function, we have to copy the values to a continuous memory. Best done using the functionality of array- there is no need to reinvent the wheel:

    from cpython cimport array
    import array
    
    def set_overlays_list(list verts):
        cdef array.array a =  array.array('f', verts)
        setOverlays(a.data.as_floats) #we already know they are floats
    
    0 讨论(0)
  • 2020-12-17 22:33

    Check out http://docs.cython.org/src/userguide/memoryviews.html. Looks like it also gives tips on how to utilize Python's built-in array module, as well as numpy.

    0 讨论(0)
  • 2020-12-17 22:51

    This is what I use for preparing arrays for passing to Cython, or C/CPP with SWIG.

    import numpy as np    
    def make_c_array(a):
        """
        Take an input numpy array and convert to being ready for use in C.
        """
        b = []
        for i in range(len(a)):
            b.append(a[i])
        a = np.array(b,dtype=np.dtype('d'),order='C')
        return a
    
    0 讨论(0)
提交回复
热议问题