Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
今回はPythonにおいてわかりにくい概念・機能の代表?でもある抽象基底クラス(abstract base class:abcまたはABC)について、特に抽象基底クラスを作るためのモジュールであるABCモジュールについて簡単に解説します。
なおこの記事における用語の使い方としては、
基本的にこのようにします。
Contents
Pythonにおける抽象基底クラス(ABC)とは、Pythonにおいてインターフェイスを実装するための1つの手段・機能です。
それではインターフェイスとは何でしょう?
プログラミングの世界におけるインターフェイスとは、大雑把にいえばクラスが持つべきデータ(属性)やメソッドを定義したものです。それを表したイメージ図が下の図です
よくプログラミングの初心者向け解説ではクラス(class)を設計図だと説明されます。そこでこのイメージ図でもそんな業界の慣習?にあわせて、設計図としてクラスA〜Cまでを示しています。その各クラスからそれぞれの製品として各インスタンスが生成されます。
ですが、いろいろな設計図にもやはり書き方のルールというものがそれぞれの企業または業界ごとにあると思います。
そうした「設計図を作るときのルール」、それが抽象基底クラス(abstract base class)だというイメージです。
そして現時点(2024年)において、実はPythonには他のプログラミング言語でいうところのこのインターフェイスという機能・仕組みは直接的には導入されていません。しかし、インターフェイスがないPythonでも、インターフェイスを事実上・間接的に実現することができる方法が用意されています。その方法の1つがABCなのです。
それではさっそくその初歩的な使用例と特徴を見ていきましょう。
ABCの作り方は大きくわけて次の2通りあります。こちらの使用例をみてください。
#### 作り方1: abcモジュールを使う ############################
from abc import ABC, abstractmethod
class MyABC_1(ABC):
# デコレータとして使う
# デコレイトされる関数(f_1)の中身は基本的に定義しない
@abstractmethod
def f_1(self):
pass
#### 作り方2: メタクラスを指定する ############################
from abc import ABCMeta
class MyABC_2(metaclass=ABCMeta):
@abstractmethod
def f_2(self):
pass
Pythonではこうして2つの方法で抽象的クラス(上ではMyABC_1とMyABC_2)を作ることができます。
そしてどちらもメソッドに@abstractmethodというデコレータを使っています。抽象基底クラスにはこのデコレータを使うことが基本となります。
作り方1のようにabcモジュールからabc.ABCを承継するが便利でわかりやすいと思います。またそれで十分だと思います。したがって以下ではabc.ABCを承継する作り方1の方法を前提とした解説をしていきます。
この抽象基底クラスも当然クラスです。そしてクラスといえばインスタンスを作って使うのが基本となるわけですが、実は抽象基底クラスからはインスタンスを直接つくることはできません。下の画像をみてください。
矢印①において、2つの抽象基底クラスからそれぞれインスタンスを作ろうとしていますが、まずその部分のコードの下に波線部があらわれます。これはVSCode上で「そうしたコードはおかしいですよ」というメッセージです。
そしてその波線部にマウスカーソルを合わせると矢印②のような警告メッセージが実際に現れます。
上で作った2つの抽象基底クラスにはそれぞれ@abstractmethodデコレータが使われています。これら2つの抽象基底クラスからインスタンスを作ってみます。
insta_1 = MyABC_1()
insta_2 = MyABC_2()
これを実行すると、次のようにエラーがでます。
>>> insta_1 = MyABC_1()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: Can’t instantiate abstract class MyABC_1 with abstract method f_1
>>> insta_2 = MyABC_2()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: Can’t instantiate abstract class MyABC_2 with abstract method f_2
@asbtractmehtodデコレータを使ったABCではこのように直接インスタンスを作ることができません。しかし同デコレータを使わなければ可能です。
上で使用した@abstractmethodデコレータは、メソッドを抽象的メソッド(抽象的メソッドと言葉は私が勝手に作った言葉です)へと変更する役割を持ちます。
抽象的メソッドになったメソッドは、ABCのサブクラスにおいてそのメソッドを定義しないと例外が発生します。
たとえば、
class SubClass_1(MyABC_1):
# def f_1(self):
# pass
def f_3(self):
pass
insta_3 = SubClass_1()
このコードでは、
というものです。
このコードをVSCodeで書くと、
このように波線部の警告が登場します。これは、抽象的クラスMyABC_1で定義し、@abstractmethodで抽象的メソッドとしたdef f_1をそのサブクラスで定義していないからです。
そしてそのまま実行すれば、次のようにエラーとなります。
Traceback (most recent call last):
File “”, line 1, in
TypeError: Can’t instantiate abstract class SubClass_1 with abstract method f_1
もちろん、上コードからコメントアウトを外して次のように書けば例外は発生しません。
class SubClass_1(MyABC_1):
def f_1(self):
pass
def f_3(self):
pass
insta_3 = SubClass_1()
@abstractmethodデコレータはこのようにサブクラスで必ず実装しなければならないメソッドを実装し忘れることを防いでくれるわけですね。忘れずに、◯◯メソッドを定義しろ!という示してくれるわけです。
以上ものすごく簡単に抽象的クラス(ABC)についてその基本を解説しましたが、つまるところ抽象基底クラスをメリットは、
という2つが大きなものとなるでしょう。
なお実際の現場では、抽象基底クラス(ABC)を使うことはフレームワークそのものをゼロから開発する場合や大規模な開発をしたりする場合などを除けば、あまり使わないほうが良いとされているようです。
深く考えずになんでもかんでも抽象化したり、コードの再利用性だけを追求したりするのはコード全体の理解を妨げることにつながりかねないリスクがあるからです。