Python
python3
多重継承

多重継承したスーパークラスから同一名のメソッドを選択取得して動的メソッドオーバーライド、注意点

継承について書かれた記事にコメントしたのですが、記事を削除されてしまったようなので、新たな記事として投稿します。
車クラスを継承してスポーツカー、エコカー、自動運転車などのクラスを作った後、運転モードを指定することで選ばれたスーパークラスのメソッドを取得して自分のメソッドとして動的メソッドオーバーライドする多重継承クラスを定義しました。
しかし、実行結果が妙なのです。

class Car(object):

    def __init__(self, name):
        self.name = name

    def display(self, text):
        print(self.name + ': ' + text);

    def run(self):
        self.display('run')


class SportsCar(Car):

    def run(self):
        self.display('run fast')


class EcoCar(Car):

    def run(self):
        self.display('run ecofriendly')


class AutomaticDrivingCar(Car):

    def run(self):
        self.display('run automatic')


class AutomaticDrivingSportyEcoCar(AutomaticDrivingCar, SportsCar, EcoCar):

    def set_mode_automatic(self):
        self.run = super().run

    def set_mode_sports(self):
        self.run = super(SportsCar, self).run

    def set_mode_eco(self):
        self.run = super(EcoCar, self).run

    def set_mode_normal(self):
        self.run = super(AutomaticDrivingCar, self).run


car1 = Car("Cedan")
car1.run()

car2 = SportsCar("GT-R")
car2.run()

car3 = AutomaticDrivingSportyEcoCar("Google")
car3.run()
car3.set_mode_sports()
car3.run()
car3.set_mode_eco()
car3.run()
car3.set_mode_normal()
car3.run()
car3.set_mode_automatic()
car3.run()
実行結果
Cedan: run
GT-R: run fast
Google: run automatic
Google: run ecofriendly
Google: run
Google: run fast
Google: run automatic

処理の最後に Google の自動運転スポーティエコカーの運転モードを
自動運転⇒スポーツモード⇒エコモード⇒通常モード⇒自動運転モード
の順に切り替えたつもりだったのですが、実行結果をみると、
自動運転⇒エコモード⇒通常モード⇒スポーツモード⇒自動運転モード
の順で表示されてしまいました。

インターネットで探してみたところ、superの引数にクラス名を指定した場合、スキップするクラスを指定したことになり、多重継承順序で次のクラスが取得されるようです。
なので、狙ったクラスの一つ前のクラスを指定するといいようです。

class AutomaticDrivingSportyEcoCar(AutomaticDrivingCar, SportsCar, EcoCar):

    def set_mode_automatic(self):
        self.run = super().run

    def set_mode_sports(self):
        self.run = super(AutomaticDrivingCar, self).run

    def set_mode_eco(self):
        self.run = super(SportsCar, self).run

    def set_mode_normal(self):
        self.run = super(EcoCar, self).run


car3 = AutomaticDrivingSportyEcoCar("Google")
car3.run()
car3.set_mode_sports()
car3.run()
car3.set_mode_eco()
car3.run()
car3.set_mode_normal()
car3.run()
car3.set_mode_automatic()
car3.run()
実行順序
Google: run automatic
Google: run fast
Google: run ecofriendly
Google: run
Google: run automatic

参考:
https://docs.python.jp/3/library/functions.html#super

super([type[, object-or-type]])
探索の順序は、 type 自身が飛ばされるのをのぞいて getattr() で使われるのと同じです。

原文 https://docs.python.org/3.6/library/functions.html#super

The search order is same as that used by getattr() except that the type itself is skipped.