この記事では、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 では、abstractclassmethod
やabstractstaticmethod
のようなデコレータを用いて抽象クラスメソッドや抽象スタティックメソッドを定義していましたが、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
それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ