sec04 - Pythonの継承を徹底解説:親クラスと子クラス、super()とオーバーライドの使い方
スポンサーリンク

なぜ継承が必要なのか

クラスを使ってプログラムを書いていくと、「似ているけれど少しだけ違うクラス」を作りたくなることがあります。

たとえば、「Car(車)」という基本的なクラスがあったとして、そこから「ElectricCar(電気自動車)」や「GasCar(ガソリン車)」を作りたい場合です。すべての車に共通する動作(たとえば、走る・ブレーキをかけるなど)は、親クラスにまとめて定義します。そして、それぞれの車の特徴(電気自動車なら充電、ガソリン車なら給油)は、子クラスにだけ書くようにすると、共通のコードを重複して書かずに済み、保守性や拡張性が向上します。

このように、共通部分をまとめ、個別の違いを分けて整理する仕組みを継承と呼びます。

Pythonの継承の基本文法と書き方

子クラスのクラス名の後に丸カッコを付け、その中に親クラス名を記述します。

子クラスは、親クラスのクラス変数・インスタンス変数・メソッドを継承し、呼び出すことができます。

# 親クラス
class Parent:
    parent_class_var = 'parent_class_var'

    def parent_method(self):
        print('parent_method')
        self.parent_instance_var = 'parent_instance_var'

# 子クラス(親クラスを継承)
class Child(Parent):
    # 子クラスには変数やメソッドの定義を書かなくても、親クラスの変数やメソッドを使うことができる
    pass

子クラスのインスタンスを作り、メソッドの呼び出しや、クラス変数・インスタンス変数の情報を出力してみます。

child_instance = Child()
child_instance.parent_method()

print(Child.parent_class_var)
print(child_instance.parent_class_var)
print(child_instance.parent_instance_var)

出力結果:

parent_method
parent_class_var
parent_class_var
parent_instance_var

親クラスで定義されたメソッドの呼び出しや、変数の値を参照することができています。

スポンサーリンク

Carクラスを使って継承を体験してみよう

まずは「車の基本クラス」として Car を作り、そこから「電気自動車」と「ガソリン車」を派生させてみましょう。

# 親クラス(共通の機能を持つ)
class Car:
    def __init__(self, brand, model):
        self.brand = brand
        self.model = model

    def drive(self):
        print(f'{self.brand}の{self.model}が走ります。')

    def brake(self):
        print(f'{self.brand}の{self.model}がブレーキをかけます。')

# 子クラス① 電気自動車
class ElectricCar(Car):
    # 電気自動車は充電する
    def charge(self):
        print(f'{self.brand}の{self.model}を充電しています。')

# 子クラス② ガソリン車
class GasCar(Car):
    # ガソリン車は給油する
    def refuel(self):
        print(f'{self.brand}の{self.model}にガソリンを給油しています。')


# 子クラスのインスタンスを作成
my_tesla = ElectricCar('Tesla', 'Model 3')
my_toyota = GasCar('Toyota', 'Corolla')

# 各クラスのメソッドを呼び出し
my_tesla.drive()   # 親クラスから継承
my_tesla.charge()  # 子クラス固有

my_toyota.brake()   # 親クラスから継承
my_toyota.refuel()  # 子クラス固有
TeslaのModel 3が走ります。
TeslaのModel 3を充電しています。
ToyotaのCorollaがブレーキをかけます。
ToyotaのCorollaにガソリンを給油しています。

このように、ElectricCarGasCar はそれぞれ独自の機能を持ちつつ、共通のdrive()brake()メソッドは親クラス Car から受け継いで使っています。子クラスは親の機能をそのまま使えるので、共通の処理を書き直す必要はありません。差分だけ追加します。

オーバーライドとは?子クラスで親クラスのメソッドを上書きする方法

子クラスでは、親クラスと同じ名前のメソッドを定義すると、親クラスのメソッドを上書き(オーバーライド)することができます。

たとえば、電気自動車はエンジン音がしないので、先ほどのコードのElectricCarクラスにdrive()メソッドを追加し、オーバーライドしてみましょう。

class ElectricCar(Car):
    def drive(self):
        print(f'{self.brand}の{self.model}が静かに走ります(電気モーター駆動)。')

呼び出すときは、これまでと同様にインスタンス.メソッド()の形式で記述します。

my_tesla = ElectricCar('Tesla', 'Model 3')
my_tesla.drive()   # オーバーライドしたメソッドを実行

出力例:

TeslaのModel 3が静かに走ります(電気モーター駆動)。

オーバーライドすると、親クラスで定義した内容は出力(実行)されません。子クラスで定義された内容のみ実行されます。

super()の使い方:親クラスの処理を呼び出す

子クラスでオーバーライドしても、親クラスの処理も残したい場合があります。そのときに使うのが super() です。super().メソッド()の形式で記述します。

先ほどのdrive()メソッドにsuper().drive()を追加します。

class ElectricCar(Car):
    def drive(self):
        super().drive()  # 親クラスのdrive()を呼び出す
        print(f"{self.brand}の{self.model}は静かに加速します。")
my_tesla = ElectricCar('Tesla', 'Model 3')
my_tesla.drive()   # オーバーライドしたメソッドを実行

出力例:

TeslaのModel 3が走ります。
TeslaのModel 3は静かに加速します。

super() を使うと、親クラスの処理を残したまま、子クラス特有の追加動作を行えます。

もし、__init__()メソッドでsuper()を使う場合は、上記と同じ形式でsuper().__init__()と記述します。

Python継承の最終コード例とまとめ

# 親クラス(共通の機能を持つ)
class Car:
    def __init__(self, brand, model):
        self.brand = brand
        self.model = model

    def drive(self):
        print(f'{self.brand}の{self.model}が走ります。')

    def brake(self):
        print(f'{self.brand}の{self.model}がブレーキをかけます。')

# 子クラス① 電気自動車
class ElectricCar(Car):
    # driveメソッドのオーバーライド
    def drive(self):
        super().drive()  # 親クラスのdrive()を呼び出す
        print(f"{self.brand}の{self.model}は静かに加速します。")

    # 電気自動車は充電する
    def charge(self):
        print(f"{self.brand}の{self.model}を充電しています。")

# 子クラス② ガソリン車
class GasCar(Car):
    # ガソリン車は給油する
    def refuel(self):
        print(f'{self.brand}の{self.model}にガソリンを給油しています。')


# Tesla
my_tesla = ElectricCar('Tesla', 'Model 3')
my_tesla.drive()   # 親クラスをオーバーライドしたもの
my_tesla.brake()   # 親クラスから継承
my_tesla.charge()  # 子クラス固有

# Toyota
my_toyota = GasCar('Toyota', 'Corolla')
my_toyota.drive()   # 親クラスから継承
my_toyota.brake()   # 親クラスから継承
my_toyota.refuel()  # 子クラス固有

出力結果:

TeslaのModel 3が走ります。
TeslaのModel 3は静かに加速します。
TeslaのModel 3がブレーキをかけます。
TeslaのModel 3を充電しています。
ToyotaのCorollaが走ります。
ToyotaのCorollaがブレーキをかけます。
ToyotaのCorollaにガソリンを給油しています。

親クラスの共通処理と子クラス固有の処理を組み合わせると、再利用性が高く、わかりやすい設計になります。

スポンサーリンク