Шаг 138.
Основы языка Python. Объектно-ориентированное программирование (ООП). Множественное наследование

    На этом шаге мы рассмотрим способ организации и особенности использования множественного наследования .

    В определении класса в круглых скобках можно указать сразу несколько базовых классов через запятую. Рассмотрим множественное наследование на примере.

class Class1: # Базовый класс для класса Class2
    def func1 (self):
        print ("Метод func1() класса Class")

class Class2(Class1): # Класс Class2 наследует	класс Class1
    def func2(self):
        print("Метод func2() класса Class2")

class Class3 (Class1) : # Класс Class3 наследует класс Classl
    def func1(self) :
        print ("Метод func1() класса Class3")
    def func2(self):
        print ("Метод func2() класса Class3")
    def func3(self):
        print ("Метод func3() класса Class3")
    def func4(self):
        print ("Метод func4() класса Class3")

class Class4 (Class2, Class3): # Множественное наследование
    def func4(self):
        print ("Метод func4() класса Class4")

c = Class4() #  Создаем экземпляр класса  Class4
c.func1()    #  Выведет: Метод func1() класса Class3
c.func2()    #  Выведет: Метод func2() класса Class2
c.func3()    #  Выведет: Метод func3() класса Class3
c.func4()    #  Выведет: Метод func4() класса Class4
Архив с файлом можно взять здесь.

    Результат работы приложения:

Метод func1() класса Class3
Метод func2() класса Class2
Метод func3() класса Class3
Метод func4() класса Class4

    Метод func1() определен в двух классах: Class1 и Class3. Так как вначале просматриваются все базовые классы, непосредственно указанные в определении текущего класса, метод func1() будет найден в классе Class3 (поскольку он указан в числе базовых классов в определении Class4), а не в классе Class1.

    Метод func2() также определен в двух классах: Class2 и Class3. Так как класс Class2 стоит первым в списке базовых классов, то метод будет найден именно в нем. Чтобы наследовать метод из класса Class3, следует указать это явным образом. Переделаем определение класса Class3 из предыдущего примера и наследуем метод func2() из класса Class3:

.   .   .   .   .
class Class4 (Class2, Class3): # Множественное наследование
    #  Наследуем func2() из класса Class3, а не из класса Class2
    func2 = Class3.func2
    def func4(self):
        print ("Метод func4() класса Class4")

c = Class4() #  Создаем экземпляр класса  Class4
c.func1()    #  Выведет: Метод func1() класса Class3
c.func2()    #  Выведет: Метод func2() класса Class2
c.func3()    #  Выведет: Метод func3() класса Class3
c.func4()    #  Выведет: Метод func4() класса Class4
Архив с файлом можно взять здесь.

    Результат работы приложения:

Метод func1() класса Class3
Метод func2() класса Class3
Метод func3() класса Class3
Метод func4() класса Class4

    Вернемся к первому примеру. Метод func3() определен только в классе Class3, поэтому метод наследуется от этого класса. Метод func4(), определенный в классе Class3, переопределяется в производном классе.

    Если же искомый метод найден в производном классе, то вся иерархия наследования просматриваться не будет.

    Для получения перечня базовых классов можно воспользоваться атрибутом __bases__.

    В качестве значения атрибут возвращает кортеж. В качестве примера выведем базовые классы для всех классов из предыдущего примера:

.   .   .   .   .
print(Class1.__bases__)
print(Class2.__bases__)
print(Class3.__bases__)
print(Class4.__bases__)
Архив с файлом можно взять здесь.

    Результат работы приложения:

(,)
(<class '__main__.Class1'>,)
(<class '__main__.Class1'>,)
(<class '__main__.Class2'>, <class '__main__.Class3'>)

    Приведенный ниже пример проиллюстрирует порядок поиска идентификаторов при сложной иерархии множественного наследования:

class Class1: x = 10
class Class2(Class1): pass
class Class3(Class2): pass
class Class4(Class3): pass
class Class5(Class2): pass
class Class6(Class5): pass
class Class7(Class4, Class6): pass
c = Class7()
print(c.x)      
print(Class7.__mro__)      
Архив с файлом можно взять здесь.

    Последовательность поиска атрибута х будет такой:

  Class7 -> Class4 -> Class3 - > Class6 -> Class5 -> Class2 -> Class1

    Получить всю цепочку наследования позволяет атрибут __mro__:

print(Class7.__mro__)      

    Результат выполнения:

10
(<class '__main__.Class7'>, <class '__main__.Class4'>, <class '__main__.Class3'>, 
<class '__main__.Class6'>, <class '__main__.Class5'>, <class '__main__.Class2'>, 
<class '__main__.Class1'>, <class 'object'>)

    На следующем шаге мы рассмотрим примеси.




Предыдущий шаг Содержание Следующий шаг