我有一些在cython中实现为cdef class
的类。在客户端python代码中,我想使用多个继承来构成类,但是出现类型错误。这是一个最小的可重现示例:
In [1]: %load_ext cython
In [2]: %%cython
...: cdef class A:
...: cdef int x
...: def __init__(self):
...: self.x = 0
...: cdef class B:
...: cdef int y
...: def __init__(self):
...: self.y = 0
...:
In [3]: class C(A, B):
...: pass
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-83ef5091d3a6> in <module>()
----> 1 class C(A, B):
2 pass
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict
有什么办法可以解决这个问题?
docs说:
一个Python类可以从多种扩展类型中继承,只要遵循用于多种继承的常规Python规则(即所有基类的C布局必须兼容)。
鉴于上面的琐碎示例,我试图理解这可能意味着什么。
答案 0 :(得分:2)
非常严格。据我所知,除了其中一个类外,其他所有类都必须为空。空类可以具有def
个函数,但不能具有cdef
个函数或cdef
个属性。
参加Cython课程:
cdef class A:
cdef int x
这将转换为C代码:
struct __pyx_obj_2bc_A { // the name might be different
PyObject_HEAD
int x;
};
基本上只是一个C结构,其中包含基本的Python对象和一个整数。
限制是,派生类必须仅包含一个PyObject_HEAD
,并且其PyObject*
也应可解释为struct __pyx_obj_2bc_A*
或struct __pyx_obj_2bc_B*
。
在您的情况下,两个整数x
和y
会尝试占用相同的内存(因此发生冲突)。但是,如果其中一种类型为空,则它们将共享PyObject_HEAD
,但不会进一步冲突。
cdef
函数导致将struct __pyx_vtabstruct_2bc_A *__pyx_vtab;
添加到结构中(因此它不为空)。它包含函数指针,这些函数指针使继承的类可以覆盖cdef
函数。
具有两个从公共第三类继承的cdef
类是可以的,如果公共第三类不为空,则会发生这种情况。
cdef class A:
cdef int x
cdef class B(A):
cdef int y
cdef class C(A):
pass
class D(B,C):
pass
如果您确实想研究算法的详细信息,则执行此检查的内部Python代码是函数best_base
。
关于“有没有办法解决这个问题?”答案是“不是真的”。您最好的选择可能是合成而不是继承(即让类C
持有A
和B
对象,而不是继承自A
和B
)< / p>