Множественное наследование классов cthon cthon
У меня есть некоторые классы, реализованные как 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 всех базовых классов должны быть совместимы).
Я пытаюсь понять, что это может означать, учитывая приведенный выше тривиальный пример.
1 ответ
Это довольно ограничено. Насколько я могу судить, все классы, кроме одного, должны быть пустыми. Пустые классы могут иметь 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
)