На этом шаге мы рассмотрим способ организации и особенности использования множественного наследования .
В определении класса в круглых скобках можно указать сразу несколько базовых классов через запятую. Рассмотрим множественное наследование на примере.
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'>)
На следующем шаге мы рассмотрим примеси.