cython cdef类的多重继承

时间:2018-10-06 22:51:03

标签: python cython multiple-inheritance

我有一些在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布局必须兼容)。

鉴于上面的琐碎示例,我试图理解这可能意味着什么。

1 个答案:

答案 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*

在您的情况下,两个整数xy会尝试占用相同的内存(因此发生冲突)。但是,如果其中一种类型为空,则它们将共享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持有AB对象,而不是继承自AB)< / p>