在 cython cdef class 中创建 python 属性时的奇怪行为
Strange behaviour when creating python attributes in cython cdef class
我们已经给出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 访问,所以我已添加到 Stack class cdef public pC_Obj_A obj_a
和 cdef public pC_Obj_B obj_b
.这些对象是 C 结构指针的包装器。
当我用中间包装器初始化这些对象时,即 Obj_A_Wrap
一切都很好。
当我直接初始化这些对象之一时,即 self.obj_a._c_self = obj_c._c_a
也一切正常。
当 obj_a
和 obj_b
都被直接初始化时(# Not Working
代码的一部分)我的 C 库有奇怪的行为,包括 C_File_A
和 C_File_B
和 C 结构定义。该行为类似于内存损坏,或覆盖内存中不应覆盖的某些部分。
我不知道为什么直接初始化会导致这种奇怪的行为。也许你知道?
我找到了问题的解决方案。当我试图解决这个问题时,我只打印了给定对象的 _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
函数class:
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
一切都很好!
我们已经给出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 访问,所以我已添加到 Stack class cdef public pC_Obj_A obj_a
和 cdef public pC_Obj_B obj_b
.这些对象是 C 结构指针的包装器。
当我用中间包装器初始化这些对象时,即 Obj_A_Wrap
一切都很好。
当我直接初始化这些对象之一时,即 self.obj_a._c_self = obj_c._c_a
也一切正常。
当 obj_a
和 obj_b
都被直接初始化时(# Not Working
代码的一部分)我的 C 库有奇怪的行为,包括 C_File_A
和 C_File_B
和 C 结构定义。该行为类似于内存损坏,或覆盖内存中不应覆盖的某些部分。
我不知道为什么直接初始化会导致这种奇怪的行为。也许你知道?
我找到了问题的解决方案。当我试图解决这个问题时,我只打印了给定对象的 _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
函数class:
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
一切都很好!