cython cdef 的多重继承 类
Multiple inheritance of cython cdef classes
我有一些 类 在 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 说:
A Python class can inherit from multiple extension types provided that the usual Python rules for multiple inheritance are followed (i.e. the C layouts of all the base classes must be compatible).
鉴于上面的简单示例,我试图理解这可能意味着什么。
它非常受限制。据我所知,除了 classes 中的一个必须为空。空 classes 可以有 def
函数,但不能有 cdef
函数或 cdef
属性。
使用 Cython class:
cdef class A:
cdef int x
转换为 C 代码:
struct __pyx_obj_2bc_A { // the name might be different
PyObject_HEAD
int x;
};
本质上只是一个包含基本 Python 对象内容和一个整数的 C 结构。
限制是派生的 class 必须只包含一个 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;
添加到结构中(因此它不是空的)。这包含允许继承的 classes 覆盖 cdef
函数的函数指针。
有两个 cdef
class 继承自共同的第三个 class 是可以的,如果共同的第三个 class 不为空。
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
。
关于 "is there any way to get round this?",答案是 "not really." 你最好的选择可能是组合而不是继承(即 class C
持有 A
和 B
对象,而不是继承自 A
和 B
)
我有一些 类 在 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 说:
A Python class can inherit from multiple extension types provided that the usual Python rules for multiple inheritance are followed (i.e. the C layouts of all the base classes must be compatible).
鉴于上面的简单示例,我试图理解这可能意味着什么。
它非常受限制。据我所知,除了 classes 中的一个必须为空。空 classes 可以有 def
函数,但不能有 cdef
函数或 cdef
属性。
使用 Cython class:
cdef class A:
cdef int x
转换为 C 代码:
struct __pyx_obj_2bc_A { // the name might be different
PyObject_HEAD
int x;
};
本质上只是一个包含基本 Python 对象内容和一个整数的 C 结构。
限制是派生的 class 必须只包含一个 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;
添加到结构中(因此它不是空的)。这包含允许继承的 classes 覆盖 cdef
函数的函数指针。
有两个 cdef
class 继承自共同的第三个 class 是可以的,如果共同的第三个 class 不为空。
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
。
关于 "is there any way to get round this?",答案是 "not really." 你最好的选择可能是组合而不是继承(即 class C
持有 A
和 B
对象,而不是继承自 A
和 B
)