abc --- 抽象基底クラス¶
ソースコード: Lib/abc.py
このモジュールは Python に PEP 3119 で概要が示された 抽象基底クラス (ABC) を定義する基盤を提供します。なぜこれが Python に付け加えられたかについてはその PEP を参照してください。 (ABC に基づいた数の型階層を扱った PEP 3141 と numbers モジュールも参照してください。)
collections モジュール には、抽象基底クラス から派生するいくつかの具象クラスがある。もちろん、これらはさらに派生させることができる。さらに、 collections.abc サブモジュールには、クラスやインスタンス が特定のインターフェース 、たとえば 、 hashable であるか、 mapping であるかをテストするために使用できる抽象基底クラス があります。
このモジュールは、 抽象基底クラスを定義するためのメタクラス ABCMeta と、 継承を利用して抽象基底クラスを代替的に定義するヘルパークラス ABC を提供します。
- class abc.ABC¶
メタクラスとして
ABCMetaを持つヘルパークラスです。このクラスを使うことで、ABCを継承するだけで抽象基底クラスを作成でき、しばしば混乱しがちなメタクラスの使用を避けることができます。例えば:from abc import ABC class MyABC(ABC): pass
ABCの型はABCMetaなので、ABCを継承する場合も、メタクラスを使う際の通常の注意が必要です。 多重継承ではメタクラスが競合する場合があります。 また、metaclassキーワードにABCMetaを直接指定して、抽象基底クラスを定義することもできます。from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
Added in version 3.4.
- 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 ABC class MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
バージョン 3.3 で変更: クラスデコレータとして使うことができるように、登録されたサブクラスを返します。
バージョン 3.4 で変更:
register()の呼び出しを検出するには、get_cache_token()関数を使えます。
また、次のメソッドを抽象基底クラスの中でオーバーライドできます:
- __subclasshook__(subclass)¶
(クラスメソッドとして定義しなければなりません。)
subclassがこの ABC のサブクラスとみなされるか調べます。 このメソッドでissubclass()の動作をさらにカスタマイズすれば、ABC のサブクラスとみなしたいクラスごとにregister()を呼ぶ必要がなくなります。 (このクラスメソッドは、ABC の__subclasscheck__()メソッドから呼び出されます。)このメソッドは
True、False、NotImplementedのいずれかを返す必要があります。Trueを返すと、subclassはこの ABC のサブクラスとみなされます。Falseを返すと、通常ならサブクラスであっても、subclassはこの ABC のサブクラスとはみなされません。NotImplementedを返すと、通常の仕組みでサブクラスの検査を続けます。
この概念のデモとして、次の ABC 定義の例を見てください:
class Foo: def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable(ABC): @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__()は、__dict__に__iter__()メソッドを持つクラスをMyIterableとみなします。 また、__mro__リストからたどれる基底クラスのいずれかがそのメソッドを持つ場合も、同様にみなします。最後の行では、
__iter__()メソッドを定義していないFooも、MyIterableの仮想的サブクラスにしています (Fooは__len__()と__getitem__()に基づく古いイテラブルプロトコルを使っています)。 ただし、これによってget_iteratorがFooのメソッドとして使えるようになるわけではないので、別途定義しています。
abc モジュールは、次のデコレータも提供します。
- @abc.abstractmethod¶
抽象メソッドを示すデコレータです。
このデコレータを使うには、クラスのメタクラスが
ABCMetaまたはその派生クラスである必要があります。 メタクラスがABCMetaから派生しているクラスは、すべての抽象メソッドと抽象プロパティがオーバーライドされるまで、インスタンス化できません。 抽象メソッドは、通常の super 呼び出しの仕組みで呼び出せます。@abstractmethodは、プロパティやデスクリプタの抽象メソッドを宣言するためにも使えます。クラスへの抽象メソッドの動的な追加や、作成済みのメソッドやクラスが抽象であるかどうかの変更は、
update_abstractmethods()関数を使う場合にのみサポートされます。@abstractmethodが影響するのは、通常の継承によるサブクラスだけです。 ABC のregister()メソッドで登録された「仮想的サブクラス」には影響しません。@abstractmethodを他のメソッドデスクリプタと組み合わせる場合は、次の例のように最も内側のデコレータとして適用してください。class C(ABC): @abstractmethod def my_abstract_method(self, arg1): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, arg2): ... @staticmethod @abstractmethod def my_abstract_staticmethod(arg3): ... @property @abstractmethod def my_abstract_property(self): ... @my_abstract_property.setter @abstractmethod def my_abstract_property(self, val): ... @abstractmethod def _get_x(self): ... @abstractmethod def _set_x(self, val): ... x = property(_get_x, _set_x)
抽象基底クラスの仕組みと正しく連携するには、デスクリプタが抽象であることを
__isabstractmethod__で示す必要があります。 一般に、デスクリプタを構成するメソッドのいずれかが抽象なら、この属性をTrueにするべきです。 例えば、Python の組み込み@propertyは次と同等の処理を行います。class Descriptor: ... @property def __isabstractmethod__(self): return any(getattr(f, '__isabstractmethod__', False) for f in (self._fget, self._fset, self._fdel))
注釈
Java の抽象メソッドと違い、これらの抽象メソッドは実装を持ち得ます。この実装は
super()メカニズムを通してそれをオーバーライドしたクラスから呼び出すことができます。これは協調的多重継承を使ったフレームワークにおいて super 呼び出しの終点として有効です。
abc モジュールは、次の古いデコレータもサポートしています。
- @abc.abstractclassmethod¶
Added in version 3.2.
バージョン 3.3 で非推奨:
@classmethodと@abstractmethodを組み合わせて使えるようになったため、このデコレータは不要になりました。抽象クラスメソッドを表す、組み込みの
classmethodのサブクラスです。 それ以外の点では@abstractmethodと同様です。抽象メソッドに
@classmethodデコレータを適用すれば、抽象であると正しく認識されるようになったため、この特別なデコレータは非推奨です。class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, arg): ...
- @abc.abstractstaticmethod¶
Added in version 3.2.
バージョン 3.3 で非推奨:
@staticmethodと@abstractmethodを組み合わせて使えるようになったため、このデコレータは不要になりました。抽象静的メソッドを表す、組み込みの
staticmethodのサブクラスです。 それ以外の点では@abstractmethodと同様です。抽象メソッドに
@staticmethodデコレータを適用すれば、抽象であると正しく認識されるようになったため、この特別なデコレータは非推奨です。class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(arg): ...
- @abc.abstractproperty¶
バージョン 3.3 で非推奨:
@property、@property.getter、@property.setter、@property.deleterを@abstractmethodと組み合わせて使えるようになったため、このデコレータは不要になりました。抽象プロパティを表す、組み込みの
propertyのサブクラスです。抽象メソッドに
@propertyデコレータを適用すれば、抽象であると正しく認識されるようになったため、この特別なデコレータは非推奨です。class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
この例は読み出し専用のプロパティを定義しています。プロパティを構成するメソッドの1つ以上を abstract にすることで、読み書きできる抽象プロパティを定義することができます:
class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...
構成するメソッド全てが abstract でない場合、abstract と定義されたメソッドのみが、具象サブクラスによってオーバーライドする必要があります:
class D(C): @C.x.setter def x(self, val): ...
abc モジュールは、次の関数も提供します。
- abc.get_cache_token()¶
現在の抽象基底クラスのキャッシュトークンを返します。
このトークンは、仮想サブクラスのための抽象基底クラスの現在のバージョンを特定する (等価性検査をサポートしている) 不透明なオブジェクトです。 任意のABCでの
ABCMeta.register()の呼び出しごとに、トークンは変更されます。Added in version 3.4.
- abc.update_abstractmethods(cls)¶
抽象クラスが抽象であるかどうかを再計算する関数です。 クラスを作成した後で、その抽象メソッドを実装したり変更したりした場合に呼び出してください。 通常はクラスデコレータの中から呼び出します。
クラスデコレータとして使えるように、
clsを返します。clsがABCMetaのインスタンスでなければ、何もしません。注釈
この関数は、
clsのスーパークラスがすでに更新されていることを前提とします。 サブクラスの更新は行いません。Added in version 3.10.
脚注