Pythonで抽象クラスを作る方法!!

takkun
どうも!たっくんです!

オブジェクト指向でプログラミングをしていると、複数のクラスに対して共通性を持たせるために抽象クラス(Abstract)を作りたくなることがありませんか!?

Mayaerで身近なところですと、Qt(PySide/PyQt)の「QAbstractItemModel」「QAbstractSlider」等があります。特に装飾をせずに見よう見まね?でクラスを作ると、以下のようになっている場合があるかと思います。

class AbstractItem(object):
    def create(self):
        pass

    def delete(self):
        pass
        
class MayaItem(AbstractItem):
    def create(self):
        pass
    
item = MayaItem()

しかし!

抽象クラスの特徴として、以下の物があります。

  1. 抽象クラスからインスタンスを作成できない。
  2. オーバーライドが必須になっているメソッドがある。

残念ながら上記のコードでは、抽象クラスからインスタンスを作成してしまったり、オーバーライドの必須を強要することができません。。。名ばかりの抽象クラス。。。(´・ω・`)

そこで!

pythonの標準モジュールの「abc」を使います!抽象クラスを作る時のポイントになるのは、メタクラスと、デコレーションの設定です!(`・ω・´)ゞ

モジュールのimport

ネームスペースを書かないようにするのが一般的?なようなので、以下のようにimportすると良いと思います!

from abc import ABCMeta, abstractmethod

メタクラスの設定

抽象クラスにしたいクラスに、メタクラス「ABCMeta」を設定します。これを忘れると、うまく抽象クラスにすることができません(´・ω・`)

from abc import ABCMeta, abstractmethod

class AbstractItem(object):
    __metaclass__ = ABCMeta
    def create(self):
        pass
        
    def delete(self):
        pass

続いて、オーバーライドが必須としたいメソットにデコレーション「@abstractmethod」を設定していきます。今回は「create」と「delete」両方とも設定したいと思います。

from abc import ABCMeta, abstractmethod

class AbstractItem(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def create(self):
        pass
        
    @abstractmethod
    def delete(self):
        pass

すると!「AbstractItem」のインスタンスを作ろうとすると、以下のようにエラーします(*´ω`*)b

item = AbstractItem()
# Error: Can't instantiate abstract class AbstractItem with abstract methods create, delete 

続いて!「AbstractItem」を継承した「MayaItem」を作成します。ここではあえて、メソッド「delete」を実装しないようにしてみます。

from abc import ABCMeta, abstractmethod

class AbstractItem(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def create(self):
        pass
        
    @abstractmethod
    def delete(self):
        pass
        
class MayaItem(AbstractItem):
    def create(self):
        pass

インスタンスを作ろうとすると、、、

item = MayaItem()
# Error: Can't instantiate abstract class MayaItem with abstract methods delete

不完全な継承をしていると、きっちりエラーを吐いてくれます!(ホントはインスタンス作る前にエラーしてほしいけど・・・)

これで、Pythonでもキッチリとした抽象クラスが作れると思います!(`・ω・´)ゞ