Множественное наследование и порядок разрешения методов в Python

В этом руководстве вы узнаете о множественном наследовании Python и о том, как в Python работает  порядок разрешения методов (Method Resolution Order).

Содержание

Введение в множественное наследование в 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) для поиска правильного метода для вызова. Рассмотрим следующий пример:

Пример порядка разрешения методов (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 по отдельности.

Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *