【Python】レッスン5-09:抽象クラスを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:抽象クラス

この記事の練習問題を解くために必要な知識:
1.基礎文法、2.制御構造、3.関数とスコープ、4.データ構造、5.オブジェクト指向

<<前のページ Python記事一覧 次のページ>>

Pythonの「抽象クラス」とは

この章ではPythonにおける「抽象クラス」の意味や使い方を学習します。用語の解説が不要な方はここをクリックして練習問題へ飛びましょう。




プログラムを作成する際、コードを再利用しやすく、メンテナンスしやすく設計することが重要です。

抽象クラスはその設計に役立つ概念で、共通の基盤を提供しつつ具象クラスでの独自実装を促す仕組みです。

【初心者向け】Pythonのオブジェクト指向を分かりやすくまとめた概念図。 特にクラスの継承、オーバーライド、抽象クラス、ミックスインクラス、データクラス、静的メソッドの関係性を視覚的に理解できるようまとめている。

抽象クラスとは?

抽象クラスとは、直接インスタンス化されることを想定しない基底クラス(継承されることを前提としたクラス)です。

主に以下のような目的で使用されます:

  • 子クラスで実装する必要がある共通のメソッドを定義
  • 設計の一貫性を保証

Pythonではabcモジュール(Abstract Base Classesの略)を用いて抽象クラスを作成します。

抽象クラスの基本構文

Pythonで抽象クラスを作成するには、abcモジュールのABCクラスと@abstractmethodデコレーターを使用します。

以下に基本的な構文を示します:

from abc import ABC, abstractmethod # abcモジュールのインポート

class Animal(ABC):   # 抽象クラスとしてAnimalを定義
    @abstractmethod  # 子クラスは必ずspeakメソッドを実装しなければならない
    def speak(self): # 抽象メソッド
        pass

    @abstractmethod  # 子クラスは必ずmoveメソッドを実装しなければならない
    def move(self):  # 抽象メソッド
        pass
  • Animalクラスは抽象クラスとして定義されています。
  • @abstractmethodデコレーターを使うことで、子クラスでの必須実装メソッドを指定します。
  • 抽象メソッドは具体的な処理を持たず、子クラスからオーバーライドされる前提となっています。

抽象クラスを直接インスタンス化しようとするとエラーが発生します。

抽象クラスの使用例

以下は具体的な使用例です。動物クラスを基底クラスとして作成し、子クラスで動作を具体化します。

from abc import ABC, abstractmethod # abcモジュールのインポート

class Animal(ABC):     # 抽象クラスの定義
    @abstractmethod
    def speak(self):   # 抽象メソッドの定義
        pass

    @abstractmethod    # 抽象メソッドの定義
    def move(self):
        pass

class Dog(Animal):     # Animalクラスを継承したDogクラスの定義
    def speak(self):   # 抽象メソッドの実装 & オーバーライド
        return "Woof!"

    def move(self):    # 抽象メソッドの実装 & オーバーライド
        return "Runs on four legs"

class Bird(Animal):    # Animalクラスを継承したBirdクラスの定義
    def speak(self):   # 抽象メソッドの実装
        return "Chirp!"

    def move(self):    # 抽象メソッドの実装
        return "Flies in the sky"

# 使用例
dog = Dog()         # インスタンス生成
bird = Bird()       # インスタンス生成

print(dog.speak())  # Woof!
print(dog.move())   # Runs on four legs
print(bird.speak()) # Chirp!
print(bird.move())  # Flies in the sky

# 二つの子クラスは同じ抽象クラスを継承したが、出力はクラスごとに異なる

この例ではAnimalという抽象クラスを基にしてDogBirdというクラスを作成しています。

子クラスでAnimalクラスのメソッドを実装することで、各動物の特性を定義できます。

まとめ

抽象クラスはオブジェクト指向プログラミングにおいて設計の一貫性を保ち、コードの再利用性を向上させる強力なツールです。

特に大規模なプロジェクトやチーム開発で活用されます。以下のような場合に使用を検討すると良いでしょう:

  • 子クラス間で共通する基盤の定義が必要なとき
  • 設計段階で特定のメソッドの実装を強制したいとき

抽象クラスを適切に活用することで、より堅牢で保守性の高いプログラムを構築できます。

抽象クラスの練習問題:犬と鳥の動作をクラスで表現しよう

動物を抽象的に表現するクラスを作成し、それを基に犬と鳥のクラスを実装してください。

動物クラスでは「鳴き声」と「移動方法」を抽象的に定義し、それぞれの具体的なクラスで実装します。

最後に犬と鳥の鳴き声と移動方法を表示するプログラムを完成させましょう。

問題の詳細条件

以下の要件に従ってコードを完成させてください。

  1. Animalという名前の抽象クラスを定義すること。
    • make_soundメソッド: 鳴き声を表す抽象メソッドとして定義する。
    • moveメソッド: 移動方法を表す抽象メソッドとして定義する。
  2. DogクラスをAnimalクラスから継承して作成すること。
    • make_soundメソッド: 犬の鳴き声として「ワンワン!」を返す。
    • moveメソッド: 犬の移動方法として「走り回る」を返す。
  3. BirdクラスをAnimalクラスから継承して作成すること。
    • make_soundメソッド: 鳥の鳴き声として「ピヨピヨ!」を返す。
    • moveメソッド: 鳥の移動方法として「空を飛ぶ」を返す。
  4. メイン関数で以下を実施すること:
    • DogクラスとBirdクラスのインスタンスを生成する。
    • それぞれのインスタンスの鳴き声と移動方法を出力する。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

犬の鳴き声: ワンワン!
犬の移動方法: 走り回る
鳥の鳴き声: ピヨピヨ!
鳥の移動方法: 空を飛ぶ

【ヒント】難しいと感じる人だけ見よう

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:abcモジュールからABCとabstractmethodをインポート
2:Animalという抽象クラスを定義
  □ make_soundという抽象メソッドを定義
  □ moveという抽象メソッドを定義
3:DogというクラスをAnimalを継承して定義
  □ make_soundというメソッドをオーバーライド
  □ moveというメソッドをオーバーライド
4:BirdというクラスをAnimalを継承して定義
  □ make_soundというメソッドをオーバーライド
  □ moveというメソッドをオーバーライド
5:main関数を定義
  □ Dogクラスのインスタンスを生成し、dog変数に代入
  □ Birdクラスのインスタンスを生成し、bird変数に代入
  □ printを使って「犬の鳴き声」を出力
  □ printを使って「犬の移動方法」を出力
  □ printを使って「鳥の鳴き声」を出力
  □ printを使って「鳥の移動方法」を出力
6:if文で__name__が”main“か判定
  □ main関数を呼び出す

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

from abc import ABC, abstractmethod  # abcモジュールをインポート

# 動物の基底クラス(抽象クラス)
class Animal(ABC):
    """【穴埋め問題1】
    ここにmake_soundという抽象メソッドを定義してください。
    """

    """【穴埋め問題2】
    ここにmoveという抽象メソッドを定義してください。
    """

# 犬クラス(Animalを継承)
class Dog(Animal):
    """【穴埋め問題3】
    ここにmake_soundというメソッドをオーバーライドして、
    犬の鳴き声「ワンワン!」を返すコードを書いてください。
    """

    """【穴埋め問題4】
    ここにmoveというメソッドをオーバーライドして、
    犬の移動方法「走り回る」を返すコードを書いてください。
    """

# 鳥クラス(Animalを継承)
class Bird(Animal):
    """【穴埋め問題5】
    ここにmake_soundというメソッドをオーバーライドして、
    鳥の鳴き声「ピヨピヨ!」を返すコードを書いてください。
    """

    """【穴埋め問題6】
    ここにmoveというメソッドをオーバーライドして、
    鳥の移動方法「空を飛ぶ」を返すコードを書いてください。
    """

# メイン処理
def main():
    """
    メイン関数。犬と鳥のインスタンスを作成し、それぞれの動作を表示します。
    """
    """【穴埋め問題7】
    ここでDogクラスのインスタンスを作成し、変数dogに代入するコードを書いてください。
    """

    """【穴埋め問題8】
    ここでBirdクラスのインスタンスを作成し、変数birdに代入するコードを書いてください。
    """

    """【穴埋め問題9】
    ここで犬の鳴き声と移動方法を出力するコードを書いてください。
    """

    """【穴埋め問題10】
    ここで鳥の鳴き声と移動方法を出力するコードを書いてください。
    """

# メイン処理の実行
if __name__ == "__main__":
    """【穴埋め問題11】
    ここでmain関数を呼び出すコードを書いてください。
    """

以上がこの問題の穴埋めコードです。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。



問題の答え合わせと解説

この問題の一つの正解例とそのコードの解説を以下に示します。

一つの正解例

例えば以下のようなプログラムが考えられます。

from abc import ABC, abstractmethod  # abcモジュールをインポート

# 動物の基底クラス(抽象クラス)
class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        """動物の鳴き声を出力する抽象メソッド"""
        pass

    @abstractmethod
    def move(self):
        """動物がどのように移動するかを定義する抽象メソッド"""
        pass

# 犬クラス(Animalを継承)
class Dog(Animal):
    def make_sound(self):
        """犬の鳴き声を出力"""
        return "ワンワン!"

    def move(self):
        """犬の移動方法"""
        return "走り回る"

# 鳥クラス(Animalを継承)
class Bird(Animal):
    def make_sound(self):
        """鳥の鳴き声を出力"""
        return "ピヨピヨ!"

    def move(self):
        """鳥の移動方法"""
        return "空を飛ぶ"

# メイン処理
def main():
    """
    メイン関数。犬と鳥のインスタンスを作成し、それぞれの動作を表示します。
    """
    # 犬と鳥のインスタンスを生成
    dog = Dog()
    bird = Bird()

    # 犬の鳴き声と動作
    print("犬の鳴き声:", dog.make_sound())
    print("犬の移動方法:", dog.move())

    # 鳥の鳴き声と動作
    print("鳥の鳴き声:", bird.make_sound())
    print("鳥の移動方法:", bird.move())

# メイン処理の実行
if __name__ == "__main__":
    main()

正解例の詳細解説

今回作成したコードをブロック毎に解説します。

抽象クラスとモジュールのインポート

from abc import ABC, abstractmethod  # abcモジュールをインポート
  • abcモジュールは抽象クラスを定義するためのモジュールです。
  • 抽象クラスは直接インスタンス化できない基底クラスで、子クラスに特定のメソッドを実装させるための仕組みを提供します。

抽象クラスの定義

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        """動物の鳴き声を出力する抽象メソッド"""
        pass

    @abstractmethod
    def move(self):
        """動物がどのように移動するかを定義する抽象メソッド"""
        pass
  • Animalクラスは抽象クラスです。ABCクラスを継承して作成されます。
  • @abstractmethodを使うと、そのメソッドを子クラスで必ず実装するように強制できます。
  • この例ではmake_sound(鳴き声)とmove(移動方法)が抽象メソッドです。

具体クラスの実装

class Dog(Animal):
    def make_sound(self):
        return "ワンワン!"

    def move(self):
        return "走り回る"

class Bird(Animal):
    def make_sound(self):
        return "ピヨピヨ!"

    def move(self):
        return "空を飛ぶ"
  • DogクラスBirdクラスはAnimalクラスを継承しています。
  • それぞれmake_soundmoveを具体的に実装しています。
  • これによりDogは「ワンワン!」と鳴き、「走り回る」と移動し、Birdは「ピヨピヨ!」と鳴き、「空を飛ぶ」と移動します。

メイン関数

def main():
    dog = Dog()  # 犬のインスタンス生成
    bird = Bird()  # 鳥のインスタンス生成

    # 犬の鳴き声と動作
    print("犬の鳴き声:", dog.make_sound())
    print("犬の移動方法:", dog.move())

    # 鳥の鳴き声と動作
    print("鳥の鳴き声:", bird.make_sound())
    print("鳥の移動方法:", bird.move())
  • main関数ではDogBirdのインスタンスを生成し、それぞれの鳴き声と移動方法を表示します。
  • make_soundmoveメソッドは抽象クラスAnimalで定義されているため、すべての子クラスで実装されています。

まとめ

  • 抽象クラスは共通の設計を強制し、コードの再利用性を高める重要な仕組みです。
  • この例ではAnimal抽象クラスを基にしてDogBirdという具体クラスを作成しました。
  • 抽象メソッドを活用すると、クラス設計の一貫性を保つことができます。

プログラムを通してオブジェクト指向プログラミングの基礎を深く理解できたのではないでしょうか?

<<前のページ Python記事一覧 次のページ>>

質問用コンタクトフォーム

この記事はAIを用いて書いた記事です。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。






    Python記事一覧へ戻る
    トップページへ戻る