Cython:创建C结构数组

时间:2019-03-17 03:38:49

标签: python cython

几天来我一直在尝试各种方法,但似乎缺少一些关键要素。我正在尝试创建一个C结构数组,并从Python字典中填充这些结构。我想在类定义或某些全局函数中捕获它,因为我将从代码中的多个位置使用它。

根据请求,我已将代码解构为最低版本,并将其全部放在一个文件中:

FOO_BOOL    = 1
FOO_BYTE    = 2
FOO_STRING  = 3

cdef union Data:
    bint flag
    int byte
    char *string

ctypedef struct bar_t:
    char name[512]
    int type
    Data data

cdef class BarArray:
    cdef bar_t *array;
    cdef size_t nbars;

    def __cinit__(self, number):
        self.array = <bar_t*>malloc(number * sizeof(bar_t))
        if not self.array:
            raise MemoryError()
        self.nbars = number

    def load(self, keyvals:dict):
        kvkeys = list(keyvals.keys())
        if len(kvkeys) > <int>self.ninfo:
            # this should never happen except in development
            # so raise an error to let them know
            raise IndexError()
        n = 0
        for key in kvkeys:
            if keyvals[key][1] == 'bool':
                self.array[n].type = FOO_BOOL
                self.array[n].data.flag = keyvals[key][0]
            elif keyvals[key][1] == 'byte':
                self.array[n].type = FOO_BYTE
                self.array[n].data.byte = keyvals[key][0]
            elif keyvals[key][1] == 'string':
                self.array[n].type = FOO_STRING
                if isinstance(keyvals[key][0], str):
                    pykey = keyvals[key][0].encode('ascii')
                else:
                    pykey = keyvals[key][0]
                try:
                    self.array[n].data.string = strdup(pykey)
                except:
                    raise ValueError("String value declared but non-string provided")
            else:
                raise TypeError("UNRECOGNIZED VALUE TYPE")
            n += 1

    @property
    def array(self):
        return self.array

    @property
    def nbars(self):
        return self.nbars


cdef class FooClass():
    cdef bar_t *array
    cdef size_t sz
    def __cinit__(self, sz):
        self.bar = BarArray(sz)

    def loadarray(self, keyvals:dict):
        self.bar.load(keyvals)
        self.array = <bar_t*>self.bar.array
        while n < self.sz:
            print("INFO [", n, "]: ", self.array[n].name, self.array[n].type)
            n += 1

尝试编译时,出现以下错误:

warning: foobar.pyx:28:16: cdef variable 'array' declared after it is used

Error compiling Cython file:
------------------------------------------------------------
...
                raise TypeError("UNRECOGNIZED VALUE TYPE")
            n += 1

    @property
    def array(self):
        return self.array
                  ^
------------------------------------------------------------

foobar.pyx:67:19: Cannot convert 'bar_t *' to Python object

我读过一个地方,您必须将其强制转换为,但这也会产生错误。我最终设法找到了解决编译错误的方法,但是返回的数组包含垃圾。

任何建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

将指针发送回Python并没有实际意义(因此会看到错误)。我想您想做的就是定义Python访问器函数doReturn(newProds).when(enumOneSpy).getProdNames(); __setitem__

__getitem__

请注意,您需要注意内存管理。因为您不能依靠指向继续存在的Python字符串中保存的数据的指针,所以需要为它们自己分配内存。这也意味着您需要确保在销毁类或替换数组元素时将其释放。我跳过了编写此代码的步骤,因为它很大程度上取决于您使用的C库。