Множественное наследование классов 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)

Другие вопросы по тегам