将C结构传递给Cython并转换为Python numpy数组

时间:2018-09-20 20:47:08

标签: python cython

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 */
  

以下是使用pyx的Cython 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

在该类中,编译时出现以下错误:

  

“ Pythonout {aka struct Pythonout}”没有名为“ n”的成员

     

“ Pythonout {aka struct Pythonout}”没有名为“ x”的成员

调用对象值pnx.npnx.x时。

1 个答案:

答案 0 :(得分:0)

您的代码至少有两个问题。

  1. 导致编译错误的琐碎问题:在C中,您将结构属性称为pxpn,而在Cython中,您将它们称为xn 。这意味着Cython生成的代码与C标头不匹配。使这些保持一致。

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

    这表明Numpy现在拥有x中的数据,并负责对其进行分配。但是,假设您具有Python代码:

    x1 = PyClassInstance.x
    x2 = PyClassInstance.x
    

    您现在拥有两个Numpy数组,每个数组都相信自己拥有相同的数据,并且都将尝试对其进行重新分配。 (类似地,如果您从不访问x,则永远不会释放pnx.x)您可能应该做的是让PyClass实例负责释放其pnx.x(在{{ 1}}函数)。然后在您的__dealloc__属性中执行

    x

    现在,Numpy数组将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... 实例视为拥有数据。