PythonのAbstractクラスの実装
状況
Pythonのクラス継承をよく使うものの、特に抽象クラスの実装をサブクラスに強制させないような実装をしていた(他人が読むコードではないので)。 実際どうやるんだろうと調べたのでサンプルコード付きで残しておく。
ポイント
- 抽象クラスでmetaclass引数に対してABCMetaを与えて継承
- 抽象化する関数に @abc.abstractmethod のデコレータをつける
Pythonのドキュメント
このデコレータを使うには、クラスのメタクラスが ABCMeta かそれを継承したものである必要があります。
サンプルコード
サブクラスで抽象化メソッドを実装せずエラーが出力される例
from abc import abstractmethod from abc import ABCMeta class Abstract(metaclass=ABCMeta): def __init__(self): super().__init__() pass @abstractmethod def show_message(self): pass class SubClass(Abstract): def __init__(self): super().__init__() sub = SubClass() sub.show_message() # TypeError: Can't instantiate abstract class SubClass with abstract methods show_message
サブクラスで抽象化メソッドを実装しているのでエラーは出力されない例
from abc import abstractmethod from abc import ABCMeta class Abstract(metaclass=ABCMeta): def __init__(self): super().__init__() pass @abstractmethod def show_message(self): pass class SubClass(Abstract): def __init__(self): super().__init__() def show_message(self): print("hoge hoge") sub = SubClass() sub.show_message() # hoge hoge # Process finished with exit code 0
抽象化メソッドを指定するデコレータをつけていないのでエラーが出力されない例
from abc import abstractmethod from abc import ABCMeta class Abstract(metaclass=ABCMeta): def __init__(self): super().__init__() pass def show_message(self): pass class SubClass(Abstract): def __init__(self): super().__init__() sub = SubClass() sub.show_message() # Process finished with exit code 0
一瞬はまった点
最初、普通にABCMetaクラスを継承させたら怒られました。
class Abstract(ABCMeta)
みたいな。
こちらの記事が参考になったのですが、metaclassに指定したクラスはインスタンス生成時の挙動(継承メソッドの実装有無など)の規定・チェックに用いられるみたいですね。
ABCMetaはabstractmethodのデコレータが付与されたメソッドが、サブクラスの作成しようとしているインスタンスに含まれているか確認してくれてるのだと思います。