<一覧に戻る

クラスの継承

オブジェクト指向プログラミング(OOP)における継承は、既存のクラス(スーパークラスまたは親クラス)の属性やメソッドを新しいクラス(サブクラスまたは子クラス)に引き継ぐ仕組みです。これにより、コードの再利用性が向上し、クラス間の関係性を明確に表現することができます。このセクションでは、Pythonを用いてクラスの継承の基本概念と実装方法を初心者にもわかりやすく解説します。

継承とは?

継承は、既存のクラスの機能を新しいクラスに拡張・再利用するための仕組みです。継承を利用することで、コードの重複を避け、より整理された設計を行うことができます。

継承の利点

  • コードの再利用: 既存のクラスの機能を再利用することで、開発効率が向上します。
  • 拡張性: 新しい機能を追加する際に、既存のコードを変更せずに拡張できます。
  • メンテナンス性の向上: 共通の機能をスーパークラスに集約することで、変更が容易になります。

Pythonでの継承の基本

Pythonでは、サブクラスを定義する際に、スーパークラスの名前を括弧内に記述します。以下に、基本的な継承の構文と例を示します。

基本構文

class スーパークラス:
    # スーパークラスの定義
    pass

class サブクラス(スーパークラス):
    # サブクラスの定義
    pass

サンプルコード

以下に、Animal クラスをスーパークラスとして、Dog クラスをサブクラスとして継承する例を示します。

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

    def speak(self):
        raise NotImplementedError("サブクラスでこのメソッドを実装してください。")

    def move(self):
        print(f"{self.name} は移動しています。")

class Dog(Animal):
    def speak(self):
        return f"{self.name} はワンワンと鳴きます。"

class Cat(Animal):
    def speak(self):
        return f"{self.name} はニャーニャーと鳴きます。"

説明

  • スーパークラス Animal:
  • __init__ メソッドで name 属性を初期化します。
  • speak メソッドは、サブクラスで実装することを期待しています。
  • move メソッドは、全ての動物が移動する共通の動作を定義しています。

  • サブクラス DogCat:

  • スーパークラス Animal を継承しています。
  • speak メソッドをオーバーライドして、それぞれ犬と猫の鳴き声を定義しています。

オブジェクトの生成とメソッドの呼び出し

スーパークラスとサブクラスから生成されたオブジェクトを用いて、メソッドを呼び出す方法を見てみましょう。

# サブクラスのインスタンスを生成
dog = Dog("Buddy")
cat = Cat("Lucy")

# メソッドの呼び出し
print(dog.speak())  # 出力: Buddy はワンワンと鳴きます。
print(cat.speak())  # 出力: Lucy はニャーニャーと鳴きます。

# スーパークラスのメソッドを呼び出す
dog.move()  # 出力: Buddy は移動しています。
cat.move()  # 出力: Lucy は移動しています。

説明

  • dogcat は、それぞれ DogCat クラスから生成されたオブジェクトです。
  • speak メソッドはサブクラスでオーバーライドされているため、各動物特有の鳴き声が出力されます。
  • move メソッドはスーパークラスで定義されているため、全ての動物オブジェクトで共通の動作として実行されます。

super() 関数の使用

super() 関数は、サブクラスからスーパークラスのメソッドや属性にアクセスするために使用されます。これにより、スーパークラスの機能を拡張・利用することが容易になります。

サンプルコード

以下に、Dog クラスでスーパークラスの __init__ メソッドを呼び出す例を示します。

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

    def speak(self):
        raise NotImplementedError("サブクラスでこのメソッドを実装してください。")

    def move(self):
        print(f"{self.name} は移動しています。")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # スーパークラスのコンストラクタを呼び出す
        self.breed = breed      # サブクラス特有の属性を追加

    def speak(self):
        return f"{self.name} はワンワンと鳴きます。"

    def fetch(self, item):
        print(f"{self.name} は {item} を取りに行きます。")

説明

  • super().__init__(name):
  • スーパークラス Animal__init__ メソッドを呼び出し、name 属性を初期化します。
  • これにより、サブクラスでスーパークラスの初期化処理を再利用できます。

  • サブクラス特有の属性 breed:

  • Dog クラスに特有の breed 属性を追加しています。

  • 新しいメソッド fetch:

  • 犬が特定のアイテムを取りに行く動作を定義しています。

使用例

# Dogクラスのインスタンスを生成
dog = Dog("Buddy", "Golden Retriever")

# メソッドの呼び出し
print(dog.speak())      # 出力: Buddy はワンワンと鳴きます。
dog.fetch("ボール")     # 出力: Buddy は ボール を取りに行きます。
dog.move()              # 出力: Buddy は移動しています。

# 属性のアクセス
print(dog.name)         # 出力: Buddy
print(dog.breed)        # 出力: Golden Retriever

多重継承

Pythonでは、サブクラスが複数のスーパークラスを継承する多重継承が可能です。これにより、複数のクラスの機能を組み合わせて新しいクラスを作成することができます。ただし、多重継承は複雑さを増すため、慎重に使用する必要があります。

サンプルコード

以下に、FlyableSwimmable という2つのスーパークラスを継承する Duck クラスの例を示します。

class Flyable:
    def fly(self):
        print(f"{self.name} は飛んでいます。")

class Swimmable:
    def swim(self):
        print(f"{self.name} は泳いでいます。")

class Duck(Animal, Flyable, Swimmable):
    def speak(self):
        return f"{self.name} はガーガーと鳴きます。"

    def quack(self):
        print(f"{self.name} がクワック!")

説明

  • スーパークラス FlyableSwimmable:
  • それぞれ飛行能力と泳泳能力を提供するクラスです。

  • サブクラス Duck:

  • スーパークラス AnimalFlyableSwimmable を継承しています。
  • speak メソッドをオーバーライドして、アヒル特有の鳴き声を定義しています。
  • 新しいメソッド quack を追加しています。

使用例

# Duckクラスのインスタンスを生成
duck = Duck("Donald")

# メソッドの呼び出し
print(duck.speak())    # 出力: Donald はガーガーと鳴きます。
duck.fly()             # 出力: Donald は飛んでいます。
duck.swim()            # 出力: Donald は泳いでいます。
duck.quack()           # 出力: Donald がクワック!

メソッドオーバーライド

メソッドオーバーライドは、スーパークラスで定義されたメソッドをサブクラスで再定義することです。これにより、サブクラス固有の動作を実装することができます。

サンプルコード

以下に、Animal クラスの move メソッドを Bird クラスでオーバーライドする例を示します。

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

    def speak(self):
        raise NotImplementedError("サブクラスでこのメソッドを実装してください。")

    def move(self):
        print(f"{self.name} は移動しています。")

class Bird(Animal):
    def speak(self):
        return f"{self.name} はチュンチュンと鳴きます。"

    # moveメソッドをオーバーライド
    def move(self):
        print(f"{self.name} は飛び回っています。")

使用例

# Birdクラスのインスタンスを生成
bird = Bird("Tweety")

# メソッドの呼び出し
print(bird.speak())  # 出力: Tweety はチュンチュンと鳴きます。
bird.move()           # 出力: Tweety は飛び回っています。

説明

  • スーパークラス Animalmove メソッド:
  • 一般的な動物の移動動作を定義しています。

  • サブクラス Bird での move メソッドのオーバーライド:

  • 鳥特有の移動動作として、「飛び回っています」というメッセージを出力するように変更しています。

isinstanceissubclass 関数

Pythonでは、オブジェクトが特定のクラスのインスタンスであるかどうか、またはクラスが特定のスーパークラスを継承しているかどうかを確認するために、isinstance 関数と issubclass 関数が提供されています。

isinstance 関数

isinstance 関数は、オブジェクトが指定されたクラスのインスタンスであるかどうかを判断します。

# 使用例
dog = Dog("Buddy", 3)
print(isinstance(dog, Dog))      # 出力: True
print(isinstance(dog, Animal))   # 出力: True
print(isinstance(dog, Cat))      # 出力: False

issubclass 関数

issubclass 関数は、あるクラスが指定されたスーパークラスを継承しているかどうかを判断します。

# 使用例
print(issubclass(Dog, Animal))    # 出力: True
print(issubclass(Cat, Animal))    # 出力: True
print(issubclass(Dog, Cat))       # 出力: False

説明

  • isinstance(dog, Dog) は、dogDog クラスのインスタンスであるため True を返します。
  • isinstance(dog, Animal) は、Dog クラスが Animal クラスを継承しているため True を返します。
  • isinstance(dog, Cat) は、dogCat クラスのインスタンスではないため False を返します。
  • issubclass(Dog, Animal) は、DogAnimal を継承しているため True を返します。
  • issubclass(Cat, Animal) は、CatAnimal を継承しているため True を返します。
  • issubclass(Dog, Cat) は、DogCat を継承していないため False を返します。

実践例:車と電気自動車のクラス継承

以下に、Car クラスをスーパークラスとして、ElectricCar クラスをサブクラスとして継承する例を示します。電気自動車固有の属性とメソッドを追加しています。

サンプルコード

class Car:
    def __init__(self, make, model, year):
        self.make = make      # インスタンス変数
        self.model = model    # インスタンス変数
        self.year = year      # インスタンス変数
        self.odometer_reading = 0  # インスタンス変数

    def description(self):
        return f"{self.year} {self.make} {self.model}"

    def read_odometer(self):
        print(f"この車の走行距離は {self.odometer_reading} キロです。")

    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("走行距離を巻き戻すことはできません。")

    def increment_odometer(self, miles):
        if miles >= 0:
            self.odometer_reading += miles
        else:
            print("走行距離を減らすことはできません。")

class ElectricCar(Car):
    def __init__(self, make, model, year, battery_size=75):
        super().__init__(make, model, year)  # スーパークラスのコンストラクタを呼び出す
        self.battery_size = battery_size    # サブクラス固有の属性

    def describe_battery(self):
        print(f"この車のバッテリー容量は {self.battery_size} kWh です。")

    def fill_gas_tank(self):
        print("この車はガソリンタンクを持っていません。")

説明

  • スーパークラス Car:
  • 車のメーカー、モデル、年式、走行距離を管理する属性を持ちます。
  • 走行距離を表示・更新・増加するメソッドを提供します。

  • サブクラス ElectricCar:

  • スーパークラス Car を継承しています。
  • 電気自動車固有の属性 battery_size を追加しています。
  • バッテリー容量を表示する describe_battery メソッドを追加しています。
  • ガソリンタンクがないことを示す fill_gas_tank メソッドをオーバーライドしています。

使用例

# ElectricCarクラスのインスタンスを生成
my_electric_car = ElectricCar("Tesla", "Model S", 2022, battery_size=100)

# メソッドの呼び出し
print(my_electric_car.description())    # 出力: 2022 Tesla Model S
my_electric_car.describe_battery()      # 出力: この車のバッテリー容量は 100 kWh です。
my_electric_car.fill_gas_tank()         # 出力: この車はガソリンタンクを持っていません。

# 走行距離の操作
my_electric_car.read_odometer()         # 出力: この車の走行距離は 0 キロです。
my_electric_car.update_odometer(1500)
my_electric_car.read_odometer()         # 出力: この車の走行距離は 1500 キロです。
my_electric_car.increment_odometer(500)
my_electric_car.read_odometer()         # 出力: この車の走行距離は 2000 キロです。

注意点

  • super() の使用:
  • サブクラスでスーパークラスのメソッドや属性にアクセスする際に便利です。
  • 特にコンストラクタでスーパークラスの初期化を行う際に使用します。

  • メソッドオーバーライド:

  • サブクラスでスーパークラスのメソッドを再定義することで、特定の動作をカスタマイズできます。
  • 必要に応じて、スーパークラスのメソッドを呼び出すことも可能です。

  • 多重継承の注意:

  • 複数のスーパークラスを継承する際は、メソッド解決順序(Method Resolution Order: MRO)を理解することが重要です。
  • 多重継承は柔軟性を提供しますが、複雑さを増すため、適切な設計が求められます。

まとめ

  • 継承は、既存のクラスの機能を再利用・拡張するための強力な仕組みです。
  • サブクラスはスーパークラスの属性やメソッドを引き継ぎ、必要に応じてオーバーライドや新しい機能の追加が可能です。
  • super() 関数を利用することで、スーパークラスのメソッドを効率的に呼び出すことができます。
  • 多重継承は複数のスーパークラスの機能を組み合わせる際に有用ですが、設計には慎重さが求められます。
  • 継承を適切に活用することで、コードの再利用性と拡張性を高め、より効率的なプログラミングが可能になります。

実際にPythonコードを書いて継承を試し、スーパークラスとサブクラスの関係性を理解することで、オブジェクト指向プログラミングの基礎をさらに深めましょう。

参考資料

出力結果: