クラス

【Python】クラスの継承の基本 ~メソッドのオーバーライド、superによる基底クラスのメソッド呼び出し ~

【Python】クラスの継承の基本 _メソッドのオーバーライド、superによる基底クラスのメソッド呼び出し _

Pythonのクラスの継承の基本と継承で理解が必要になってくるメソッドのオーバーライドsuperによる基底クラスのメソッド呼び出しについて解説します。

クラスの継承

クラスの継承(Inheritance)とは、もとになるクラスのインスタンス変数やメソッドを引き継ぎながら新しい変数やメソッドを追加したり上書きしたりする仕組みのことです。

継承のもとになるクラスを基底クラス(またはスーパークラス、親クラス)、継承して作成するクラスを派生クラス(またはサブクラス、子クラス)と呼びます。

簡単な例で見てみます。以下は、Personクラスから継承させてTeacherクラスを作る場合のイメージです。

Python 継承(基底クラス、スーパークラス、親クラス)(派生クラス、サブクラス、子クラス)

Teacherクラスは、Personが持っている変数に加えて、何の教科の担当をしているかのsubject変数を持っています。また、メソッドとして仕事内容を説明をするmyworkメソッドを持っています。

継承を用いると共通となっている変数first_name、last_nameやメソッドsay_mynameを毎回定義する必要がなくなり、プログラムの再利用性を高めることができます。

Pythonでのクラス継承

上記で例として紹介したPersonクラスとTeacherクラスをPythonで定義してみると以下のようになります。

class Person:
    """人間クラス"""

    def __init__(self, first_name=None, last_name=None):
        self.first_name = first_name
        self.last_name = last_name

    def say_myname(self):
        print(f"私の名前は、{self.last_name}{self.first_name}です。")


class Teacher(Person):
    """教師クラス"""

    def mywork(self):
        print(f"{self.last_name}{self.first_name}は教師として働いています。")


def main():
    tanaka = Teacher("太郎", "田中")
    # 親クラスのメソッドの呼び出し
    tanaka.say_myname()
    # 自分のクラスのメソッドの呼び出し
    tanaka.mywork()


if __name__ == "__main__":
    main()
【実行結果】
私の名前は、田中太郎です。
田中太郎は教師として働いています。

上記のサンプルプログラムを参考にして、継承に関するポイントを説明していきます。

class Teacher(Person):
    """教師クラス"""

    def mywork(self):
        print(f"{self.last_name}{self.first_name}は教師として働いています。")

クラスを継承する場合には、「class 派生クラス名(基底クラス名):」で定義します。また、派生クラスでのメソッドは、その中に追加していくことがことができます。

次に、クラスのインスタンス化について見ていきます。方法は簡単で、派生クラス名でインスタンス化するだけです。

def main():
    tanaka = Teacher("太郎", "田中")
    # 親クラスのメソッドの呼び出し
    tanaka.say_myname()
    # 自分のクラスのメソッドの呼び出し
    tanaka.mywork()

この時、派生クラスではsay_myname()というメソッドは定義していないわけですが、Personクラスを継承することでTeacherクラスのインスタンスから呼び出すことができています。もちろんTeacherクラスで定義したmywork()メソッドも呼び出せていることが分かります。

クラスの継承の基本的な定義は以上ですが、継承の中で重要となるメソッドのオーバーライドとsuperによる基底クラスのメソッド呼び出しについて以降で説明していきます。

メソッドのオーバーライド

継承を用いることで、基底クラスで定義されたメソッドを活用できることを見てきました。しかし、同じ目的のメソッドであっても派生クラスでは少し処理を変えたくなる場合があります。

継承をした際に、基底クラスで定義したメソッドを派生クラスで上書きすることをメソッドのオーバーライドと言います。

以下がメソッドのオーバーライドの例です。

class Person:
    """人間クラス"""

    def __init__(self, first_name=None, last_name=None):
        self.first_name = first_name
        self.last_name = last_name

    def say_myname(self):
        print(f"私の名前は、{self.last_name}{self.first_name}です。")


class Teacher(Person):
    """教師クラス"""

    def mywork(self):
        print(f"{self.last_name}{self.first_name}は教師として働いています。")

    # メソッドのオーバーライド
    def say_myname(self):
        print(f"私は、教師の{self.last_name}{self.first_name}です。")


def main():
    tanaka = Teacher("太郎", "田中")
    tanaka.say_myname()
    tanaka.mywork()


if __name__ == "__main__":
    main()
【実行結果】
私は、教師の田中太郎です。
田中太郎は教師として働いています。

メソッドのオーバーライドは、基底クラスと同じ名前のメソッドを派生クラスで定義します。

この例では、say_mynameメソッドを派生クラスで定義しています。その結果、派生クラスのTeacherクラスでインスタンス化したtanakaのsay_mynameメソッドを呼び出すと、Teacherクラスのメソッドが実行されていることが分かります。

このように基底クラスを継承することで流用できる部分は流用し、必要に応じてオーバーライドしてメソッドを定義することで、プログラムの開発効率をあげていくことができます。

superによる基底クラスのメソッド呼び出し

メソッドのオーバーライドは、派生クラスで定義したメソッドで上書きできますが、場合によっては基底クラスの処理を使いつつ、派生クラスでは差分となる処理だけを追加したいということがあります。

派生クラスから、基底クラスのメソッドを呼び出すにはsuperを使用します。

以下は、初期化をするコンストラクタ__init__をオーバーライドしつつ、superにより基底クラスの__init__を呼び出して、差分の処理だけを追加している例です。

class Person:
    """人間クラス"""

    def __init__(self, first_name=None, last_name=None):
        self.first_name = first_name
        self.last_name = last_name

    def say_myname(self):
        print(f"私の名前は、{self.last_name}{self.first_name}です。")


class Teacher(Person):
    """教師クラス"""

    def __init__(self, first_name=None, last_name=None, subject=None):
        # 親クラスのコンストラクタの呼び出し
        super().__init__(first_name, last_name)
        # 自クラスの変数初期化
        self.subject = subject

    def mywork(self):
        print(f"{self.last_name}{self.first_name}は教師として働いています。")

    def say_myname(self):
        print(f"私は、{self.subject}教師の{self.last_name}" f"{self.first_name}です。")


def main():
    tanaka = Teacher("太郎", "田中", "英語")
    tanaka.say_myname()
    tanaka.mywork()


if __name__ == "__main__":
    main()
【実行結果】
私は、英語教師の田中太郎です。
田中太郎は教師として働いています。

この例では、Teacherのコンストラクタとして、__init__をオーバーライドしています。ここでPersonクラスとの違いは、初期化の変数subjectがあるかどうかです。

first_nameやlast_nameは基底クラスのPerson側の__init__でも設定しているので、Teacherクラスでも初期化のコードを書くと二度手間になってしまいます。

そこで、基底クラスの__init__をsuper().__init__(first_name, last_name)という形で呼び出しています。これにより、基底クラス側の__init__でself.first_name, self.last_nameが設定されるので、派生クラスのTeacherでは、self.subjectを設定するコードのみでよくなります。

このように、継承とメソッドのオーバーライド、そしてオーバライドを利用することで、プログラムの再利用性を高めたコーディングをすることができます。

まとめ

Pythonのクラスの継承の基本と継承で理解が必要になってくるメソッドのオーバーライドsuperによる基底クラスのメソッド呼び出しについて解説しました。

クラスの継承(Inheritance)とは、もとになるクラスのインスタンス変数やメソッドを引き継ぎながら新しい変数やメソッドを追加したり上書きしたりする仕組みのことです。Pythonでもクラスの継承は実装可能で簡単な例を使って紹介しました。

また、基底クラスで定義したメソッドを派生クラスで上書きするオーバーライドの方法と基底クラスのメソッドをsuperで呼び出して派生クラスで使用する方法について説明しました。

オブジェクト指向プログラミングでは、クラスの継承は非常に重要な要素になってきますので基本をまずは理解してもらえたらなと思います。