【Python3】オブジェクト指向プログラミング。抽象基底クラス(ABC)を実装する。

Pythonの抽象基底クラス (Abstract Base Class, ABC)

Pythonでは抽象基底クラス (Abstract Base Class, ABC)を実装することができます。

Python3でも3.4からの機能です。

抽象基底クラスの導入については、PEPの日本語訳をしてくれている人がいます。
こちら→ http://mft.la.coocan.jp/script/python/pep-3119.html

Pythonのドキュメントの抽象基底クラスの説明はこちら→ https://docs.python.jp/3/library/abc.html

「ABCs VS ダックタイピング」という箇所には、
ABC は Python 2 に良い解決策が無かった、たとえばマッピングとシーケンスを見分けるといった問題を解決したいというものとあります。

ABCを使ってみる

from abc import ABCMeta, abstractmethod  # まずはインポート


class A(metaclass=ABCMeta):  # 抽象基底クラスAを実装
    @abstractmethod  # 子クラスではfoo()の実装を必須とする
    def foo(self):
        pass


A()  # 抽象クラスは実行できない
$ python abc.py
Traceback (most recent call last):
File "abc.py", line 10, in
A()
TypeError: Can't instantiate abstract class A with abstract methods foo

抽象クラスのAはインタンス化できませんよとエラーが発生します。

@abstractmethodは抽象メソッドを示すデコレータです。

from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass


class B(A):  # foo()を実装していないからダメ
    pass


B()
Traceback (most recent call last):
File "abc.py", line 14, in
B()
TypeError: Can't instantiate abstract class B with abstract methods foo

foo()を実装していないクラスBはインスタンス化できないよとエラーが発生します。

from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass


class B(A):
    pass


class C(A):
    def foo(self):  # ちゃんとabstractメソッドを実装しています
        print('Python Carnival')


C()  # うまく動きます
C().foo()  # Cクラスのfoo()を実行します
$ python abc.py
Python Carnival

registerメソッドで仮想的サブクラスを登録できます。

from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass


class B():
    def foo(self):  # 仮想的サブクラスでもfoo()の実装は必須
        print('Python3 ABC')


class C(A):
    def foo(self):
        print('Python Carnival')


A.register(B)  # 抽象クラスAにクラスBを登録

B().foo()
$ python abc.py
Python3 ABC