简体   繁体   中英

Passing C struct to Cython and converting to Python numpy array

main.h

ifndef MAIN_H
define MAIN_H

ifdef __cplusplus
extern "C" {
endif

typedef struct Pythonout{
    int pn;
    double *px;
}Pythonout;

struct Pythonout l1tf_main(char *ifile_y, double lambda, int rflag);


ifdef __cplusplus
}
endif

endif /* MAIN_H */

Following is the Cython pyx file using main.h

.pyx

cimport numpy as np

cdef extern from "main.h":
    ctypedef struct Pythonout:
        int n
        double *x
    cdef Pythonout l1tf_main(char *ifile_y 
                            ,double lambdaval, 
                             int rflag);

cdef class Pyclass:
    cdef Pythonout pnx

    def __cinit__(self, char *pfilename, 
                  lambdaval, rflag):
        self.pnx = l1tf_main(pfilename, 
                             lambdaval, rflag)

    @property
    def n(self):
        return self.pnx.n

    @property
    def x(self):
        cdef np.npy_float64 shape[1]
        shape[0] = <np.npy_intp> self.pnx.n
        ndarray = 
                 np.PyArray_SimpleNewFromData(1, 
                 &(self.pnx.n),np.NPY_FLOAT64, 
                 <void *> self.pnx.x)
        np.PyArray_UpdateFlags(ndarray, 
                               ndarray.flags.num 
                               | np.NPY_OWNDATA)
        return ndarray

cpdef filtered_trend(char *pfilename, double 
                     lambdaval, int rflag):
    pnx = Pyclass(pfilename, lambdaval, rflag)
    return pnx.x

In the class I am getting the following error while compiling:

'Pythonout {aka struct Pythonout}' has no member named 'n'

'Pythonout {aka struct Pythonout}' has no member named 'x'

When calling the object value pnx.n and pnx.x .

There's at least two issues with your code.

  1. The trivial issue causing the compilation errors: in C you call the struct attributes px and pn , while in Cython you call them x and n . This means that the code Cython generates does not match the C header. Make these consistent.

  2.  np.PyArray_UpdateFlags(ndarray, ndarray.flags.num | np.NPY_OWNDATA) 

    This tells Numpy that in now owns the data in x and is responsible for deallocating it. However suppose you have the Python code:

     x1 = PyClassInstance.x x2 = PyClassInstance.x 

    You now have two Numpy arrays that each believe the own the same data and will both try to deallocate it. (Similarly if you never access x then pnx.x is never deallocated) What you should probably do is have the PyClass instance be responsible for deallocating its pnx.x (in a __dealloc__ function). Then in your x property do:

     ndarray = PyArray_SimpleNewFromData(...) Py_INCREF(self) # SetBaseObject doesn't do this so you must do it manually PyArray_SetBaseObject(ndarray, self) # check return value for errors... 

    Now the Numpy array treats the PyClass instance as owning the data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM