DjangoBrothers BLOG ✍️

2020/11/01

このエントリーをはてなブックマークに追加
Python

【Python】クラスの継承とsuper()の使い方

Pythonでクラスを継承させる方法と、super()の使い方について説明します。

クラスについてのより基本的なことはこの記事に書いています。

はじめに、以下のコードをみてください。

SoccerPlayerクラスとBaseballPlayerクラス

class SoccerPlayer:
    """サッカー選手 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")

    def kick(self):
        print("キック!")

class BaseballPlayer:
    """野球選手 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")

    def catch(self):
        print("キャッチ")

SoccerPlayerクラスとBaseballPlayerクラスは、それぞれのクラスで固有のインスタンスメソッド(kickとcatch)を持っています。

一方で、self_introduceというメソッドは共通しています(全く同じコードになっている)し、保有する属性(nameとage)も共通しています。

プログラミングにおいては「同じことはなるべく繰り返し書かないようにする(DRY原則)」という考え方があります。同じコードを重複して書いている(__init__とself_introduceのコードを繰り返し書いている)上記のコードはもっと簡潔に書くことができます。

このときに使えるのが、「クラスの継承」です。 「name・age属性を持つこと」、「自己紹介メソッド(self_introduce)を持つこと」は、サッカー選手・野球選手に関わらずいわば「人」として共通している特徴なので人を表すPersonクラスを作ります。

そして、そのPersonクラスを継承したSoccerPlayerクラスとBaseballPlayerクラスを作るのです。

Personクラスを作って、処理を共通化

# Personクラスを作る → 共通のメソッド(__init__とself_introduce)はこのクラスに定義する
class Person:
    """人 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")


# クラス名の後ろに(Person)をつけて、Personクラスを継承したクラスにする
class SoccerPlayer(Person):
    """サッカー選手 クラス"""

    def kick(self):
        print("キック!")

# クラス名の後ろに(Person)をつけて、Personクラスを継承したクラスにする
class BaseballPlayer(Person):
    """野球選手 クラス"""

    def catch(self):
        print("キャッチ")

s1 = SoccerPlayer("本田", 20)
b1 = BaseballPlayer("長嶋", 30)

# SoccerPlayer・BaseBallPlayerクラスは、Personクラスを継承しているのでPersonクラスのメソッド(self_introduce)が使える
s1.self_introduce()
b1.self_introduce()
# 出力結果
私の名前は本田、20才です。
私の名前は長嶋、30才です。

メソッドの上書き(オーバーライド)

子クラスに、親クラスと同じ名前のメソッドを実装することで、親クラスのメソッドを上書きすることができます。

self_introduceメソッドを上書き

class Person:
    """人 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")


class SoccerPlayer(Person):
    """サッカー選手 クラス"""

    # 親クラスと同じ名前のメソッドを定義する。
    def self_introduce(self):
        print(f"サッカー選手をやっている{self.name}と申します。")

    def kick(self):
        print("キック!")


s1 = SoccerPlayer("本田", 20)

# 子クラスのself_introduceが実行される
s1.self_introduce()
# 出力結果
サッカー選手をやっている本田と申します。

親クラスのメソッドを呼び出したいときは以下のようsuper()を使います。

親クラスのメソッドを実行

# super(<子クラス名>, <インスタンス>)で親クラスのメソッドを実行できる
super(SoccerPlayer, s1).self_introduce()

# 出力結果(Personクラスのself_introduceが実行される)
私の名前は本田、20才です。

クラス内でもsuper()は使えます。クラス内で使う場合は、引数に子クラス名を書く必要はありません。

クラス内でsuper()を使う

class Person:
    """人 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")


class SoccerPlayer(Person):
    """サッカー選手 クラス"""

    def self_introduce(self):
        # 親クラスのメソッドを呼び出す
        super().self_introduce()
        print(f"サッカー選手をやっています。")

    def kick(self):
        print("キック!")

s1 = SoccerPlayer("本田", 20)
s1.self_introduce()

# 出力結果
私の名前は本田、20才です。
サッカー選手をやっています。

super()を__init__メソッド内で使う

superは当然__init__メソッドでも使うことができます。

以下のように、SoccerPlayerクラスの__init__内で、Personの__init__を呼び出すことで、共通属性(name, age)の値の設定処理は共通化させることができます。

__init__関数内でsuper()を使う

class Person:
    """人 クラス"""
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduce(self):
        print(f"私の名前は{self.name}、{self.age}才です。")


class SoccerPlayer(Person):
    """サッカー選手 クラス"""

    def __init__(self, name, age, is_daihyo):
        # 親クラスの__init__を呼び出す。
        super().__init__(name, age)
        # is_daihyo属性はSoccerPlayerクラス固有の属性なのでここで値設定する
        self.is_daihyo = is_daihyo

    def self_introduce(self):
        super().self_introduce()
        print(f"サッカー選手をやっています。")
        # 追加
        if self.is_daihyo:
            print("日本代表選手です。")

    def kick(self):
        print("キック!")

s1 = SoccerPlayer("本田", 20, True)

s1.self_introduce()
# 出力結果
私の名前は本田、20才です。
サッカー選手をやっています。
日本代表選手です。