【问题标题】:Strange behaviour when creating python attributes in cython cdef class在 cython cdef 类中创建 python 属性时的奇怪行为
【发布时间】:2019-11-16 09:09:01
【问题描述】:

我们已经给出了 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 访问,因此我已将 cdef public pC_Obj_A obj_acdef public pC_Obj_B obj_b 添加到 Stack 类中。这些对象是 C 结构指针的包装器。

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

当我直接初始化这些对象之一,即self.obj_a._c_self = obj_c._c_a 时,一切都很好。

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

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

【问题讨论】:

  • 尝试在__init__ 的开头添加行print(self.obj_a, self.obj_b) - 它可能会让您知道出了什么问题。请记住,您标记为“工作”的某些内容可能只是“没有以明显的方式崩溃”。

标签: cython cythonize


【解决方案1】:

我找到了我的问题的解决方案。当我试图解决这个问题时,我只打印了给定对象的 _c_self 属性,以检查指针是否正确分配,但是当我打印整个对象时,结果发现 python 对象是 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)

那么打印输出是:

print(self.obj_a, self.obj_b) # <pC_Obj_A object at 0x029FF610> <pC_Obj_B object at 0x029FF620>
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # 2134b9c 2134c08

一切都很好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-11
    • 2017-04-10
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多