#  Множественное наследование – это возможность построения дочернего класса на основе нескольких базовых.
#  В качестве примера множественного наследования построим класс графического примитива Line на основе двух классов:
#  Styles и Pos :

class Point:                                            #   Класс Point - вспомогательный класс, для хранения точки в двумерном пространстве.
    def __init__(self, x=0, y=0):
        self.__x = x
        self.__y = y

    def __str__(self):
        return f"({self.__x}, {self.__y})"


class Styles:                                           #   Класс Styles - содержит стили нашей линии (цвет и ширину)
#   def __init__(self, color="red", width=1, *args):
    def __init__(self):                                 #   Адаптируем класс Styles для множественного наследования - удаляем аргументы
        print("Инициализатор Styles")
    #   self._color = color
    #   self._width = width
    #   Pos.__init__(self, *args)                       #   Вызовем в явном виде конструктор Styles и передадим ему остаточные аргументы "green", 5
    #   super().__init__(*args)                         #   Аргументы в ф-ции super() писать не надо с версии Python 3
        super().__init__()

class Pos:                                              #   Класс Pos - содержит позиции нашей линии.
#    def __init__(self, sp: Point, ep: Point, *args):   #   Error - В конструкторе класса Pos находятся две переменные а не четыре
    def __init__(self):                                 #   Адаптируем класс Pos для множественного наследования - удаляем аргументы
        print("Инициализатор Pos")                      #   *args - добавили остаточные аргументы
    #   self._sp = sp
    #   self._ep = ep
    #   Styles.__init__(self, *args)                    #   Вызовем в явном виде конструктор Styles и передадим ему остаточные аргументы "green", 5
                                                        #   В качестве первого параметра self
    #   super().__init__(*args)                         #   Аргументы в ф-ции super() писать не надо с версии Python 3
        super().__init__()

class Line(Pos, Styles):                                #   Класс графического примитива Line на основе двух классов: Pos, Styles
                                                        #   Error - дочерний класс Line сначала вызывает конструктор класса Pos
                                                        #   Адаптируем классы Pos и Styles для множественного наследования.
    def __init__(self, sp: Point, ep: Point, color="red", width=1):    #   Пропишем конструктор, который будет принимать все четыре аргумента.
        self._sp = sp                                   #   Инициализируем соответствующие свойства внутри конструктора
        self._ep = ep
        self._color = color
        self._width = width
        super().__init__()                              # Через ф-цию super() вызываем конструктор __init__() базового класса, какого ф-ция определит самостоятельно.

    def draw(self):
        print(f"Рисование линии: {self._sp}, {self._ep}, {self._color}, {self._width}")


l = Line(Point(10, 10), Point(100, 100), "green", 5)    #   Создаем класс с следующими параметрами.
                                                        #   Error - Мы передаем не две переменные а четыре - добавим остаточные аргументы  *args в класс Pos
l.draw()                                                #   Вызовем метод draw() класса line.
                                                        #   (.sp .ep класса Pos - это "green", 5) (.color .width класса Styles - это координаты точек)
                                                        #   Мы должны помнить в каком порядке должны идти классы Point, Styles, чтоб не нарушить порядок
print( Line.__mro__ )                                   #   Для любого класса можем посмотреть последовательность дерева наследования в соответствии с описанным алгоритмом в переменной __mro__

#           Pos             Styles
#         __init__()       __init__()
#            ^                 ^
#               Line (Pos,Styles)
#                ^   draw()
#                ^
#      Функция super() позволяет обойти все классы и только один раз
#      Функция super() гарантирует, что конструкторы классов Pos и Styles будут вызваны только один раз.


# C3 – поиск в дереве наследования классов Python 3 (MRO)
#
# Очень упрощенно его можно представить так:
#
# формируется список родителей в порядке их наследования
# в конец этого списка добавляются родители этих родителей (в том же порядке (и т.д.)
# если класс встречается второй раз, то он не заносится в список.
# Более подробно об этом алгоритме можно почитать здесь:
#
# https://ru.wikipedia.org/wiki/C3-линеаризация
#
# В соответствии с алгоритмом MRO обход нашего дерева наследования будет происходить так:
#
# Line → Pos → Styles → object