Множественное наследование классов cthon cthon - PullRequest
0 голосов
/ 07 октября 2018

У меня есть некоторые классы, реализованные как 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 Ответ

0 голосов
/ 07 октября 2018

Это довольно ограничено.Насколько я могу судить, все классы, кроме одного, должны быть пустыми.Пустые классы могут иметь 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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...