クラス

【Python】ポリモーフィズムと抽象クラス、抽象メソッド

【Python】ポリモーフィズムと抽象クラス、抽象メソッド

Pythonでのポリモーフィズムと抽象クラス、抽象メソッドの扱いについて解説します。

ポリモーフィズム(polymorphism)

プログラミングでクラスを実装する際に、同じ名称のメソッドで異なる挙動を実現することをポリモーフィズム(polymorphism)と言います。

ポリモーフィズムは、多様性や多相性といったように訳されることが多いです。言葉だけですとよく分からないと思いますので、以下の簡単な例で見てみます。

以下の例は、Personクラスを継承して、TeacherクラスとDoctorクラスを定義している例です。

python ポリモーフィズム

この例で、myworkメソッドは、仕事の内容を出力するだけの簡単なメソッドです。各クラス同じ名称で呼び出したいわけですが、派生クラスの内容によって挙動を変えたくなります。Teacherクラスであれば「私の仕事は、〇〇の教師です。」と、Doctorクラスであれば「私の仕事は、〇〇科の医者です。」と出力するといった形です。

このような場合、メソッドのオーバーライドをすればよいと考えます。確かにその通りです。ただし、オーバーライドは、派生クラス側でメソッドを実装することを強制できません。継承先でメソッドをオーバーライドすることを強制したいようなケースでは、少し中途半端になります。

そこで登場するのが抽象メソッドです。また、抽象メソッドを含んだクラスを抽象クラスと言います。以降では、抽象メソッドと抽象クラスについて見ていきます。

抽象クラス、抽象メソッド

ポリモーフィズム(polymorphism)を実現するための中心的な仕組みが抽象メソッドです。抽象メソッドは、中身を持たない空のメソッドで、抽象メソッドを含んだクラスを抽象クラスと言います。

空のメソッドである抽象メソッドには機能を持たせる必要があります。その実装は、抽象クラスを継承した派生クラス内で行います。

抽象クラスを継承したクラスは、すべての抽象メソッドをオーバーライドしなければいけません。すべての抽象メソッドをオーバーライドしていない場合、派生クラスはインスタンス化することができません。

abcモジュールを用いた抽象クラス・抽象メソッドの実装

Pythonでは、抽象クラスと抽象メソッドを実現するためのモジュールとしてabcモジュールというものが使用できます。

実装例

abcモジュールを使用した抽象クラス、抽象メソッドの定義方法について以下の例で見ていきましょう。

import abc


class Person(abc.ABC):
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

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

    @abc.abstractmethod
    def mywork(self):
        pass


class Teacher(Person):
    def __init__(self, subject):
        self.__subject = subject

    @property
    def subject(self):
        return self.__subject

    @subject.setter
    def subject(self, value):
        self.__subject = value

    def mywork(self):
        print(f"私の仕事は、{self.__subject}の教師です。")


class Doctor(Person):
    def __init__(self, medical_speciality):
        self.__medical_speciality = medical_speciality

    @property
    def medical_speciality(self):
        return self.__medical_speciality

    @medical_speciality.setter
    def medical_speciality(self, value):
        self.__medical_speciality = value

    def mywork(self):
        print(f"私の仕事は、{self.__medical_speciality}の医者です。")


def main():
    person1 = Teacher("英語")
    person1.mywork()
    print("===")
    person2 = Doctor("内科")
    person2.mywork()


if __name__ == "__main__":
    main()
【実行結果】
私の仕事は、英語の教師です。
===
私の仕事は、内科の医者です。

詳細説明

以降では、上記で紹介したサンプルプログラムに関してポイントを解説していきます。

抽象クラスを定義する場合には、抽象基底クラスを定義しているabcモジュールをインポートし、以下のようにabc.ABCクラスを継承してクラスを定義します。なお、abcとは「abstruct base class」の略になっています。

import abc


class Person(abc.ABC):

抽象メソッドは、以下のように、@abc.abstructmethodデコレータを付けたメソッドとして定義します。抽象クラスは継承先で実装されることを想定しているので、中身はpassとして空にしておいて問題ありません。

@abc.abstractmethod
def mywork(self):
    pass

抽象クラスを継承したTeacherクラスやDoctorクラスでは、抽象メソッドのmyworkメソッドをオーバーライドします。

class Teacher(Person):
    ...(途中省略)...
    
    def mywork(self):
        print(f"私の仕事は、{self.__subject}の教師です。")

class Doctor(Person):
    ...(途中省略)...
    
    def mywork(self):
        print(f"私の仕事は、{self.__medical_speciality}の医者です。")

もし、抽象メソッドとなっているmyworkメソッドについて、Doctorクラスで定義を忘れた場合には、以下のようなエラーとなります。

【実行結果例】
Traceback (most recent call last):
...(省略)...
TypeError: Can't instantiate abstract class Doctor with abstract methods mywork

このように抽象クラスを定義し、抽象メソッドが継承先で実装されることを強制しつつ、ポリモーフィズム(polymorphism)を実現することができます。

まとめ

Pythonでのポリモーフィズムと抽象クラス、抽象メソッドの扱いについて解説しました。

クラスを実装する際に、同じ名称のメソッドで異なる挙動を実現することをポリモーフィズム(polymorphism)と言い、多様性や多相性といったように訳されることが多いです。

クラスを継承する際にメソッドのオーバーライドができますが、オーバーライドは、派生クラス側でメソッドを実装することを強制できません。そこで登場するのが抽象メソッドです。また、抽象メソッドを含んだクラスを抽象クラスと言います。

Pythonには、abcモジュールという抽象クラス、抽象メソッドを実装するためのモジュールがあるため例を使いながら使用方法を紹介しました。

抽象クラス、抽象メソッドについて実装方法を覚えてプログラミングでうまく使えるようになると再利用性が高いクラスを実装できるかなと思います。

Note

抽象基底クラスabcの公式ドキュメントの記載はこちらを参照してください。