在cython cdef类中创建python属性时的奇怪行为

时间:2019-11-16 09:09:01

标签: cython cythonize

我们提供了Cython代码:

cdef extern from "C_File_A.h":
    cdef struct C_Obj_A:
        pass

cdef extern from "C_File_B.h":
    cdef struct C_Obj_B:
        pass

cdef class pC_Obj_A:
    cdef const C_Obj_A * _c_self

cdef class pC_Obj_B:
    cdef const C_Obj_B * _c_self

cdef class pC_Obj_C:
    cdef const C_Obj_A * _c_a
    cdef const C_Obj_B * _c_b


cdef class Obj_A_Wrap(pC_Obj_A):
    def __init__(self, pC_Obj_C obj_c):
        self._c_self = obj_c._c_a


cdef class Obj_B_Wrap(pC_Obj_B):
    def __init__(self, pC_Obj_C obj_c):
        self._c_self = obj_c._c_b


cdef class Stack:
    cdef public pC_Obj_A obj_a
    cdef public pC_Obj_B obj_b

    def __init__(self, pC_Obj_C obj_c):
        # Working
        self.obj_a = Obj_A_Wrap(obj_c)
        self.obj_b = Obj_B_Wrap(obj_c)

        # Working
        self.obj_a._c_self = obj_c._c_a
        self.obj_b = Obj_B_Wrap(obj_c)

        # Working
        self.obj_a = Obj_A_Wrap(obj_c)
        self.obj_b._c_self = obj_c._c_b

        # Not working
        self.obj_a._c_self = obj_c._c_a
        self.obj_b._c_self = obj_c._c_b

我需要一个Python对象Stack,该对象具有可从Python访问的attrubuts,因此我将其添加到Stack类cdef public pC_Obj_A obj_acdef public pC_Obj_B obj_b中。这些对象是C结构指针的包装。

当我使用中间包装器(即Obj_A_Wrap)初始化这些对象时,一切都很好。

当我直接初始化其中一个对象(即self.obj_a._c_self = obj_c._c_a)时,一切都很好。

直接obj_aobj_b都初始化时(代码的# Not Working部分),我的C库出现奇怪的行为,包括C_File_A和{{1} }和C结构定义。该行为类似于内存损坏,或覆盖了本不应该覆盖的部分内存。

我不知道为什么直接初始化会导致这种奇怪的行为。也许你知道吗?

1 个答案:

答案 0 :(得分:1)

我找到了解决我问题的方法。当我尝试解决此问题时,我仅打印了给定对象的_c_self属性,以检查是否正确分配了指针,并且确实如此,但是当我打印整个对象时,结果发现python对象为{{1} },而不是将适当的对象声明为属性。

None

解决方案是将print(self.obj_a, self.obj_b) # 66f000c0 66f000c0 print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # None None 函数添加到cdef类:

Create

并像这样使用它:

cdef class pC_Obj_A:
    cdef const C_Obj_A * _c_self

    @staticmethod
    cdef Create(C_Obj_A * ptr):
        cdef pC_Obj_A result = pC_Obj_A()
        result._c_self = ptr
        return result

然后打印输出为:

cdef class Stack:
    cdef public pC_Obj_A obj_a
    cdef public pC_Obj_B obj_b

    def __init__(self, pC_Obj_C obj_c):
        self.obj_a = pC_Obj_A.Create(obj_c._c_a)
        self.obj_b = pC_Obj_B.Create(obj_c._c_b)

一切都很好!