Python PR

【Python】抽象クラスを定義する方法

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

この記事では、Pythonで抽象クラスを定義する方法を解説します。

抽象クラスは、継承を前提としたクラスであり、抽象クラスから派生したクラスは、全ての抽象メソッドとプロパティをオーバーライドしない限りインスタンス化することができません。

つまり抽象クラスとは、必要な定義を派生クラスにオーバーライドで実装させる機能です。

それでは、抽象クラスおよび抽象メソッドの定義の方法を見ていきましょう!!

抽象クラスを定義する

Pythonで抽象クラスを定義するには、以下のコードのようにabcモジュールのABCMetaクラスを抽象クラスとしたいクラスのメタクラスとして指定します。

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    pass

メタクラスとは?

インスタンスとしてクラスを生成するクラスのこと。Pythonでは実はtype()関数からクラスが生成されている。

# 通常のクラス定義
class Demo:
    def __init__(self) -> None:
        print('demo')

Demo()  # demo


# type() を使ったクラス定義
def __init__(self):
    print('demo')

Demo = type('Demo', (), {'__init__': __init__})
Demo()  # demo

つまり、メタクラスを変更することでインスタンスとしてクラスが生成される際の挙動をカスタマイズすることが可能となる。

または、ABCMetaをメタクラスとするヘルパークラスABCが用意されているので、こちらのクラスを継承するだけで抽象基底クラスを作成することもできます。

from abc import ABC

class MyABC(ABC):
    pass

抽象メソッドの定義

抽象メソッドを定義するには、abstractmethodデコレーターを使います。もちろん、abstractmethodデコレーターは抽象クラスでしか呼び出すことができません。

from abc import ABC, abstractmethod

class MyABC(ABC):

    # 抽象メソッド
    @abstractmethod
    def method(self):
        pass

抽象メソッドに処理を記述することも可能です。子クラスでオーバーライドする際にsuper()を通して親クラスの抽象メソッドに定義されている処理を呼び出すことができます。

また、クラスメソッドやスタティックメソッド、プロパティも抽象化することができます。

from abc import ABC, abstractmethod

class MyABC(ABC):

    # クラスメソッド
    @classmethod
    @abstractmethod
    def classmethod(cls, arg):
        ...

    # スタティックメソッド
    @staticmethod
    @abstractmethod
    def staticmethod(arg):
        ...

    # プロパティ(ゲッター)
    @property
    @abstractmethod
    def myProperty(self):
        ...
    
    # プロパティ(セッター)
    @myProperty.setter
    @abstractmethod
    def myProperty(self, val):
        ...

Python 3.2 では、abstractclassmethodabstractstaticmethodのようなデコレータを用いて抽象クラスメソッドや抽象スタティックメソッドを定義していましたが、Python 3.3 からはabstractmethodが実装されたので他のデコレーターは非推奨となりました。

抽象クラスの派生クラスを定義してみる

抽象クラスを派生させるには、抽象クラスに定義されているすべての抽象メソッドや抽象プロパティなどをオーバーロードする必要があります。オーバーロードしなかった場合はそのクラスをインスタンス化した時点でTypeErrorが送出されます。

from abc import ABC, abstractmethod

# 抽象クラス
class MyABC(ABC):

    # 抽象メソッド
    @abstractmethod
    def method(self):
        pass



# 抽象クラスから派生したサブクラス
class Child(MyABC):
    # 抽象メソッドをオーバーロードする
    def method(self):
        pass


# 抽象クラスから派生したサブクラス
class Sub(MyABC):
    # 抽象メソッドをオーバーロードしない
    pass


# インスタンス化可能
child = Child()

# インスタンス化する際に TypeError が発生する
sub = Sub()
# TypeError: Can't instantiate abstract class Sub with abstract method method

仮想的サブクラスの登録

ABCMetaを使って生成されたクラスにはregister()というメソッドが定義されています。このメソッドを使うことで指定したクラスを仮想的サブクラスとして登録することができます。登録した仮想的サブクラスは、issubclass()で判定するとサブクラスとしてみなされるようになります。

from abc import ABC, abstractmethod

class MyABC(ABC):

    # 抽象メソッド
    @abstractmethod
    def method(self):
        pass


# 自作クラス
class SubClass:
    pass

# 仮想的サブクラスとして登録
MyABC.register(SubClass)
print(issubclass(SubClass, MyABC))  # True

# 組み込みも登録可能
MyABC.register(tuple)
print(issubclass(tuple, MyABC))  # True

ちなみに、仮想的サブクラスは抽象メソッドなどをオーバーロードしなくてもいいです。

まとめ

この記事では、Pythonで抽象クラスを定義する方法を解説しました。

抽象クラスを実装する状況やメリットは以下の記事で詳しく解説してくれています。どんなときに使えばいいんだろ?と疑問をお持ちの方はぜひ読んでみてください。

外部Linkなぜ抽象クラス(Abstract)を実装するのか - Qiita

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ