首页 > 解决方案 > cython cdef 类的多重继承

问题描述

我有一些cdef class在 cython 中实现的类。在客户端 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

有没有办法解决这个问题?

文档说:

一个 Python 类可以从多个扩展类型继承,前提是遵循多继承的常用 Python 规则(即所有基类的 C 布局必须兼容)。

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

标签: pythoncythonmultiple-inheritance

解决方案


很受限制。尽我所能告诉所有人,除了其中一个类必须是空的。空类可以有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;
 };

本质上只是一个包含基本 Python 对象的 C 结构和一个整数。限制是派生类必须只包含一个PyObject_HEAD,并且它PyObject*也应该可以解释为 astruct __pyx_obj_2bc_A*或 a struct __pyx_obj_2bc_B*

在您的情况下,这两个整数xy尝试占用相同的内存(因此冲突)。但是,如果其中一种类型为空,那么它们将共享PyObject_HEAD但不会进一步冲突。

cdef函数导致 astruct __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

best_base如果您真的想研究算法的细节,那么执行此检查的内部 Python 代码就是该函数。


关于“有什么办法可以解决这个问题吗?” 答案是“不是真的”。您最好的选择可能是组合而不是继承(即让类C持有一个AandB对象,而不是从Aand继承B


推荐阅读