Множественное наследование и порядок разрешения методов в Python
В этом руководстве вы узнаете о множественном наследовании Python и о том, как в Python работает порядок разрешения методов (Method Resolution Order).
- Введение в множественное наследование в Python
- Порядок разрешения методов (MRO)
- Множественное наследование и super
Введение в множественное наследование в Python
Когда класс наследуется от одного класса, у вас есть одиночное наследование. Python позволяет классу наследовать от нескольких классов. Если класс наследуется от двух или более классов, у вас будет множественное наследование.
Чтобы расширить несколько классов, вы указываете родительские классы внутри круглых скобок() после имени дочернего класса, например:
class ChildClass(ParentClass1, ParentClass2, ParentClass3): pass
Синтаксис множественного наследования аналогичен списку параметров в определении класса. Вместо включения одного родительского класса в круглые скобки вы включаете два или более классов, разделенных запятой.
Давайте рассмотрим пример, чтобы понять, как работает множественное наследование:
- Сначала определите класс Car, имеющий метод go():
class Car: def go(self): print('Going')
- Во-вторых, определите класс Flyable, имеющий метод Fly():
class Flyable: def fly(self): print('Flying')
- В-третьих, определите FlyingCar, который наследуется от классов Car и Flyable:
class FlyingCar(Flyable, Car): pass
Поскольку FlyingCar наследует классы Car и Flyable, он повторно использует методы этих классов. Это означает, что вы можете вызывать методы go() и Fly() в экземпляре класса FlyingCar следующим образом:
if __name__ == '__main__': fc = FlyingCar() fc.go() fc.fly()
Выход:
Going Flying
Порядок разрешения методов (MRO)
Когда родительские классы имеют методы с одинаковыми именами и дочерний класс вызывает этот метод, Python использует порядок разрешения методов (MRO) для поиска правильного метода для вызова. Рассмотрим следующий пример:
- Сначала добавьте метод start() к классам Car, Flyable и FlyingCar. В методе start() класса FlyingCar вызовите метод start() класса super():
class Car: def start(self): print('Start the Car') def go(self): print('Going') class Flyable: def start(self): print('Start the Flyable object') def fly(self): print('Flying') class FlyingCar(Flyable, Car): def start(self): super().start()
Во-вторых, создайте экземпляр класса FlyingCar и вызовите метод start():
if __name__ == '__main__': car = FlyingCar() car.start()
Выход:
Start the Flyable object
Как вы можете ясно видеть из вывода, super().start() вызывает метод start() класса Flyable.
Ниже показан __mro__ класса FlyingCar:
print(FlyingCar.__mro__)
Выход:
(<class '__main__.FlyingCar'>, <class '__main__.Flyable'>, <class '__main__.Car'>, <class 'object'>)
Слева направо вы увидите FlyingCar, Flyable, Car и объект.
Обратите внимание, что объекты Car и Flyable неявно наследуются от класса объектов. Когда вы вызываете метод start() из объекта FlyingCar, Python использует путь поиска класса __mro__.
Поскольку класс Flyable находится рядом с классом FlyingCar, super().start() вызывает метод start() класса FlyingCar.
Если вы поменяете порядок классов Flyable и Car в списке, __mro__ изменится соответствующим образом. Например:
# Car, Flyable classes... class FlyingCar(Car, Flyable): def start(self): super().start() if __name__ == '__main__': car = FlyingCar() car.start() print(FlyingCar.__mro__)
Выход:
Start the Car (<class '__main__.FlyingCar'>, <class '__main__.Car'>, <class '__main__.Flyable'>, <class 'object'>)
В этом примере super().start() вместо этого вызывает метод start() класса Car, основываясь на их порядках в разрешении методов.
Множественное наследование и super
- Сначала добавьте метод __init__ в класс Car:
class Car: def __init__(self, door, wheel): self.door = door self.wheel = wheel def start(self): print('Start the Car') def go(self): print('Going')
- Во-вторых, добавьте метод __init__ в класс Flyable:
class Flyable: def __init__(self, wing): self.wing = wing def start(self): print('Start the Flyable object') def fly(self): print('Flying')
__init__ классов Car и Flyable принимает разное количество параметров. Если класс FlyingCar наследует классы Car и Flyable, его метод __init__ должен вызывать правильный метод __init__, указанный в разрешении порядка методов __mro__ класса FlyingCar.
- В-третьих, добавьте метод __init__ в класс FlyingCar:
class FlyingCar(Flyable, Car): def __init__(self, door, wheel, wing): super().__init__(wing=wing) self.door = door self.wheel = wheel def start(self): super().start()
Порядок разрешения методов класса FlyingCar:
(<class '__main__.FlyingCar'>, <class '__main__.Flyable'>, <class '__main__.Car'>, <class 'object'>)
super().__init__() вызывает __init__ класса FlyingCar. Поэтому вам необходимо передать аргумент wing методу __init__.
Поскольку класс FlyingCar не может получить доступ к методу __init__ класса Car, вам необходимо инициализировать атрибуты door и wheel по отдельности.