スポンサーリンク

コードが書ける!数式が書ける!AAが書ける!スタンプが貼れる!

無料の匿名掲示板型SNS「このはちゃんねる

新規会員募集中!

【Python】クラスの多重継承。複数のクラスから機能を引き継ぐ【入門第32回】

128, 2019-08-25

目次

クラスの多重継承とは?

こんにちは、narupoです。
今回もクラスの継承について見ていきたいと思います。
継承の中でも多重継承とよばれるものについてやります。

この多重継承を使うと、複数のクラスから機能を引き継いで新しいクラスを作ることが可能になります。

多重継承のやり方

多重継承は↓のようにします。

class Lion:
    pass


class Snake:
    pass


class Chimera(Lion, Snake):
    pass

Chimera(キメラ)というクラスが多重継承をしているクラスです。
Lion(ライオン)クラスとSnake(蛇)クラスから継承しています。
このように、多重継承をする場合は、クラス名のあとのカッコの中に、継承したいクラスをカンマ(,)区切りで並べます。
このようにすると多重継承をすることができます。

継承をしているわけなので、もちろん↓のように各クラスのメソッドなどを使うことが可能です。

class Lion:
    def scratch(self):
        print('ひっかいた!')


class Snake:
    def bite(self):
        print('噛んだ!')


class Chimera(Lion, Snake):
    pass


chimera = Chimera()
chimera.scratch()
chimera.bite()

↑のコードの実行結果は↓のようになります。

ひっかいた!
噛んだ!

このように継承を使うと、異なったクラスの機能を1つのクラスにまとめることが可能です。

同名のメソッド

さきほどのLionクラスとSnakeクラスですが、ライオンと蛇はどちらも「噛む」ことができます。
よって、↓のようにメソッドがかぶることがあり得ます。

class Lion:
    def bite(self):
        print('ライオンが噛んだ!')


class Snake:
    def bite(self):
        print('ヘビが噛んだ!')

この2つのクラスを多重継承した場合、どちらのbiteメソッドが呼ばれるのでしょうか?

class Chimera(Lion, Snake):
    pass


chimera = Chimera()
chimera.bite()

↑のコードの実行結果は↓のようになります。

ライオンが噛んだ!

Lionクラスのbiteメソッドが呼ばれました。
では、多重継承の順番を↓のように変えてみましょう。

class Chimera(Snake, Lion):
    pass

この状態で再び先ほどのコードを実行すると↓のようになります。

ヘビが噛んだ!

今度はSnakeクラスのbiteメソッドが呼ばれました。
このように、同名のメソッドがある場合は、カッコの中の左のクラスのメソッドが優先されます。
左のクラスというのは、Chimera(Snake, Lion)のカッコの中の左なので、Snakeのことですね。

MRO(Method Resolution Order)

呼ばれるメソッドの優先順位は、クラスのmroメソッド、または__mro__属性で確認することができます。

print(Chimera.mro())
print(Chimera.__mro__)

MRO(Method Resolution Order)(メソッド解決順序)とは、その名の通りメソッドを解決する順序を表しています。
たとえば↓のようなクラスがあったとします。

class Lion:
    def bite(self):
        print('ライオンが噛んだ!')


class Snake:
    def bite(self):
        print('ヘビが噛んだ!')


class Chimera(Lion, Snake):
    pass


print(Chimera.mro())

↑のコードの実行結果は↓のようになります。

[<class '__main__.Chimera'>, <class '__main__.Lion'>, <class '__main__.Snake'>, <class 'object'>]

↑のMROを見ると、最初にChimeraのメソッドが優先され、その次にLion, その次にSnake, 最後にobjectが優先されることがわかります。
このことから、Chimera, Lion, Snakeに同名のメソッドがあった場合、最初に優先されるのはChimeraのメソッドであることがわかります。
ちなみにobjectというクラスは、すべてのクラスのベースになるクラスです。
Lionクラスなどはこのクラスを明示的に継承していませんが、内部では暗黙的にこのクラスが継承されています。

__init__メソッドの呼び出し

__init__メソッドなどでインスタンス変数を初期化したい場合があります。
単一の継承ではsuperを使って親クラスの__init__を呼び出していましたが、多重継承ではどうなるのでしょうか。

class Lion:
    def __init__(self):
        print('Lion')


class Snake:
    def __init__(self):
        print('Snake')


class Chimera(Lion, Snake):
    def __init__(self):
        print('Chimera')
        super().__init__()


Chimera()

↑のコードの実行結果は↓のようになります。

Chimera
Lion

Snake__init__が呼ばれていませんね。
superはメソッドの呼び出しを良い感じに解決してくれるのですが、↑のようにクラスを書くと上手く機能しません。
これをうまく機能させるにはLionクラスとSnakeクラスの__init__メソッド内で親クラスの__init__メソッドを呼び出します。

class Lion:
    def __init__(self):
        print('Lion')
        super().__init__()


class Snake:
    def __init__(self):
        print('Snake')
        super().__init__()


class Chimera(Lion, Snake):
    def __init__(self):
        print('Chimera')
        super().__init__()


Chimera()

↑のコードの実行結果は↓のようになります。

Chimera
Lion
Snake

↑のように良い感じに__init__メソッドが呼ばれました。
これは、superが良い感じにメソッドを呼び出すようにしてくれているからです。

LionクラスとSnakeクラスの__init__メソッド内でsuperを呼び出していますが、LionクラスとSnakeクラスは明示的には何のクラスも継承していません。
先ほども書きましたが、全てのオブジェクトは暗黙的にobjectクラスを継承しています。
LionクラスとSnakeクラスはobjectクラスの__init__メソッドを呼び出しているわけですね。

注意したいのは、Chimera__init__内で呼び出しているsuper()Lionのインスタンスを取得しているということです。

複雑だなぁ

複雑だよねぇ

superを使わない__init__メソッドの呼び出し

superはなかなか動作が複雑ですが、↓のように__init__を呼び出すこともできます。

class Lion:
    def __init__(self):
        print('Lion')


class Snake:
    def __init__(self):
        print('Snake')


class Chimera(Lion, Snake):
    def __init__(self):
        print('Chimera')
        Lion.__init__(self)
        Snake.__init__(self)


Chimera()

↑のコードの実行結果は↓のようになります。

Chimera
Lion
Snake

こちらのほうが直観的にはわかりやすいですね。
__init__を呼び出す順序も開発者がコントロールできます。
ただ、この呼び出し方法はひし形継承で同じ__init__が複数回呼ばれる問題に遭遇します。
その場合はsuperを使ったほうが安全に__init__を呼び出すことができます。

おわりに

クラスの多重継承を使えるようになると、より複雑な設計が可能になります。
しかし、最近は一般的に多重継承は嫌われる傾向があるようです。
設計が複雑になってしまうからですね。
ですが、それでも必要なところで使えると便利な機能ではあります。

以上、次回に続きます。

また見てね

関連動画



投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク