28.8. abc --- 抽象基底クラス¶
バージョン 2.6 で追加.
ソースコード: Lib/abc.py
このモジュールは Python に PEP 3119 で概要が示された 抽象基底クラス (ABC) を定義する基盤を提供します。なぜこれが Python に付け加えられたかについてはその PEP を参照してください。 (ABC に基づいた数の型階層を扱った PEP 3141 と numbers モジュールも参照してください。)
The collections module has some concrete classes that derive from
ABCs; these can, of course, be further derived. In addition, the
collections module has some ABCs that can be used to test whether
a class or instance provides a particular interface, for example, if it is
hashable or if it is a mapping.
このモジュールは以下のクラスを提供します:
-
class
abc.ABCMeta¶ 抽象基底クラス(ABC)を定義するためのメタクラス。
ABC を作るときにこのメタクラスを使います。ABC は直接的にサブクラス化することができ、ミックスイン(mix-in)クラスのように振る舞います。また、無関係な具象クラス(組み込み型でも構いません)と無関係な ABC を "仮想的サブクラス" として登録できます -- これらとその子孫は組み込み関数
issubclass()によって登録した ABC のサブクラスと判定されますが、登録した ABC は MRO (Method Resolution Order, メソッド解決順)には現れませんし、この ABC のメソッド実装が(super()を通してだけでなく)呼び出し可能になるわけでもありません。 1メタクラス
ABCMetaを使って作られたクラスには以下のメソッドがあります:-
register(subclass)¶ subclass を "仮想的サブクラス" としてこの ABC に登録します。たとえば:
from abc import ABCMeta class MyABC: __metaclass__ = ABCMeta MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
また、次のメソッドを抽象基底クラスの中でオーバーライドできます:
-
__subclasshook__(subclass)¶ (クラスメソッドとして定義しなければなりません。)
subclass がこの ABC のサブクラスと見なせるかどうかチェックします。これによって ABC のサブクラスと見なしたい全てのクラスについて
register()を呼び出すことなくissubclassの振る舞いをさらにカスタマイズできます。 (このクラスメソッドは ABC の__subclasscheck__()メソッドから呼び出されます。)このメソッドは
True,FalseまたはNotImplementedを返さなければなりません。Trueを返す場合は、subclass はこの ABC のサブクラスと見なされます。Falseを返す場合は、subclass はたとえ通常の意味でサブクラスであっても ABC のサブクラスではないと見なされます。NotImplementedの場合、サブクラスチェックは通常のメカニズムに戻ります。
この概念のデモとして、次の ABC 定義の例を見てください:
class Foo(object): def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable: __metaclass__ = ABCMeta @abstractmethod def __iter__(self): while False: yield None def get_iterator(self): return self.__iter__() @classmethod def __subclasshook__(cls, C): if cls is MyIterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented MyIterable.register(Foo)
ABC
MyIterableは標準的なイテラブルのメソッド__iter__()を抽象メソッドとして定義します。ここで与えられている抽象クラスの実装は、サブクラスから呼び出すことができます。get_iterator()メソッドもMyIterable抽象基底クラスの一部ですが、抽象的でない派生クラスはこれをオーバーライドする必要はありません。ここで定義されるクラスメソッド
__subclasshook__()の意味は、__iter__()メソッドがクラスの(または__mro__でアクセスされる基底クラスの一つの)__dict__にある場合にもそのクラスがMyIterableだと見なされるということです。最後に、一番下の行は
Fooを__iter__()メソッドを定義しないにもかかわらずMyIterableの仮想的サブクラスにします(Fooは古い様式の__len__()と__getitem__()を用いたイテレータプロトコルを使っています。)。これによってFooのメソッドとしてget_iteratorが手に入るわけではないことに注意してください。それは別に提供されています。-
以下のデコレータも提供しています:
-
abc.abstractmethod(function)¶ 抽象メソッドを示すデコレータです。
このデコレータを使うにはクラスのメタクラスが
ABCMetaであるかまたは派生したものであることが求められます。ABCMetaから派生したメタクラスを持つクラスは全ての抽象メソッドおよびプロパティをオーバーライドしない限りインスタンス化できません。抽象メソッドは普通の 'super' 呼び出し機構を使って呼び出すことができます。クラスに動的に抽象メソッドを追加する、あるいはメソッドやクラスが作られた後から抽象的かどうかの状態を変更しようと試みることは、サポートされません。
abstractmethod()が影響を与えるのは正規の継承により派生したサブクラスのみで、ABC のregister()メソッドで登録された "仮想的サブクラス" は影響されません。使い方:
class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...): ...
注釈
Java の抽象メソッドと違い、これらの抽象メソッドは実装を持ち得ます。この実装は
super()メカニズムを通してそれをオーバーライドしたクラスから呼び出すことができます。これは協調的多重継承を使ったフレームワークにおいて super 呼び出しの終点として有効です。
-
abc.abstractproperty([fget[, fset[, fdel[, doc]]]])¶ 組み込みの
property()のサブクラスで、抽象プロパティであることを示します。この関数を使うにはクラスのメタクラスが
ABCMetaであるかまたは派生したものであることが求められます。ABCMetaから派生したメタクラスを持つクラスは全ての抽象メソッドおよびプロパティをオーバーライドしない限りインスタンス化できません。抽象プロパティは普通の 'super' 呼び出し機構を使って呼び出すことができます。使い方:
class C: __metaclass__ = ABCMeta @abstractproperty def my_abstract_property(self): ...
この例は読み取り専用のプロパティを定義しています。プロパティ定義の「長い」形式の宣言を使って、読み書き出来る抽象プロパティを定義することができます:
class C: __metaclass__ = ABCMeta def getx(self): ... def setx(self, value): ... x = abstractproperty(getx, setx)
注記
- 1
C++ プログラマは Python の仮想的基底クラスの概念は C++ のものと同じではないということを銘記すべきです。
