29.7。 abc —抽象基本クラス
ソースコード: :source: `Lib / abc.py`
このモジュールは、 PEP 3119 で概説されているように、Pythonで抽象基本クラス(ABC)を定義するためのインフラストラクチャを提供します。 これがPythonに追加された理由については、PEPを参照してください。 (ABCに基づく数値の型階層については、 PEP 3141 および numbers モジュールも参照してください。)
collections モジュールには、ABCから派生したいくつかの具象クラスがあります。 もちろん、これらはさらに導き出すことができます。 さらに、 collections.abc サブモジュールには、クラスまたはインスタンスが特定のインターフェイスを提供するかどうかをテストするために使用できるいくつかのABCがあります。たとえば、ハッシュ可能かどうか、マッピングかどうかなどです。
このモジュールは、ABCを定義するためのメタクラス ABCMeta と、継承を通じてABCを代わりに定義するためのヘルパークラス ABC を提供します。
- class abc.ABC
メタクラスとして ABCMeta を持つヘルパークラス。 このクラスを使用すると、 ABC から派生するだけで抽象基本クラスを作成できます。たとえば、次のように、メタクラスの使用法が混乱することはありません。
from abc import ABC class MyABC(ABC): pass
ABC のタイプはまだ ABCMeta であるため、 ABC から継承するには、メタクラスの使用に関する通常の予防措置が必要です。多重継承はメタクラスの競合につながる可能性があるためです。 メタクラスキーワードを渡し、 ABCMeta を直接使用して、抽象基本クラスを定義することもできます。次に例を示します。
from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
バージョン3.4の新機能。
- class abc.ABCMeta
抽象基本クラス(ABC)を定義するためのメタクラス。
このメタクラスを使用してABCを作成します。 ABCは直接サブクラス化でき、ミックスインクラスとして機能します。 関連のない具象クラス(組み込みクラスも含む)と関連のないABCを「仮想サブクラス」として登録することもできます。これらとその子孫は、組み込みの issubclass()関数によって登録ABCのサブクラスと見なされます。ただし、登録ABCはMRO(メソッド解決順序)に表示されず、登録ABCによって定義されたメソッド実装を呼び出すこともできません( super()を介しても)。 1
ABCMeta のメタクラスで作成されたクラスには、次のメソッドがあります。
- register(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)
(クラスメソッドとして定義する必要があります。)
サブクラスがこのABCのサブクラスと見なされるかどうかを確認します。 これは、ABCのサブクラスを検討するすべてのクラスで register()を呼び出す必要なしに、
issubclass
の動作をさらにカスタマイズできることを意味します。 (このクラスメソッドは、ABCの__subclasscheck__()
メソッドから呼び出されます。)このメソッドは、
True
、False
、またはNotImplemented
を返す必要があります。True
を返す場合、サブクラスはこのABCのサブクラスと見なされます。False
を返す場合、サブクラスは、通常は1つであっても、この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 __ (またはその基本クラスの1つに __ iter __()メソッドがあるクラスを示します、 __ mro __ リストからアクセス)も
MyIterable
と見なされます。最後に、最後の行は、 __ iter __()メソッドを定義していなくても
Foo
をMyIterable
の仮想サブクラスにします(古いスタイルの反復可能なプロトコルを使用しますが、__len__()
および__getitem__()
で定義されます)。 これにより、get_iterator
がFoo
のメソッドとして使用可能になるわけではないため、別途提供されることに注意してください。
abc モジュールは、次のデコレータも提供します。
- @abc.abstractmethod
抽象メソッドを示すデコレータ。
このデコレータを使用するには、クラスのメタクラスが ABCMeta であるか、それから派生している必要があります。 ABCMeta から派生したメタクラスを持つクラスは、その抽象メソッドとプロパティがすべてオーバーライドされない限り、インスタンス化できません。 抽象メソッドは、通常の「スーパー」呼び出しメカニズムのいずれかを使用して呼び出すことができます。 abstractmethod()は、プロパティと記述子の抽象メソッドを宣言するために使用できます。
クラスに抽象メソッドを動的に追加したり、作成されたメソッドまたはクラスの抽象化ステータスを変更しようとしたりすることはサポートされていません。 abstractmethod()は、通常の継承を使用して派生したサブクラスにのみ影響します。 ABCの
register()
メソッドで登録された「仮想サブクラス」は影響を受けません。abstractmethod()を他のメソッド記述子と組み合わせて適用する場合は、次の使用例に示すように、最も内側のデコレータとして適用する必要があります。
class C(ABC): @abstractmethod def my_abstract_method(self, ...): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ... @staticmethod @abstractmethod def my_abstract_staticmethod(...): ... @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()メカニズムを介して呼び出すことができます。 これは、協調的な多重継承を使用するフレームワークでのスーパーコールのエンドポイントとして役立つ可能性があります。
abc モジュールは、次のレガシーデコレータもサポートします。
- @abc.abstractclassmethod
バージョン3.2の新機能。
バージョン3.3以降非推奨: classmethod を abstractmethod()と一緒に使用できるようになり、このデコレータが冗長になりました。
組み込みの classmethod()のサブクラスであり、抽象クラスメソッドを示します。 それ以外は、 abstractmethod()に似ています。
classmethod()デコレータが抽象メソッドに適用されたときに抽象として正しく識別されるようになったため、この特殊なケースは非推奨になりました。
class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ...
- @abc.abstractstaticmethod
バージョン3.2の新機能。
バージョン3.3以降非推奨: staticmethod を abstractmethod()とともに使用できるようになり、このデコレータが冗長になりました。
組み込みの staticmethod()のサブクラスであり、抽象staticmethodを示します。 それ以外は、 abstractmethod()に似ています。
staticmethod()デコレータが抽象メソッドに適用されたときに抽象として正しく識別されるようになったため、この特殊なケースは非推奨になりました。
class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(...): ...
- @abc.abstractproperty
バージョン3.3以降非推奨: プロパティ、
property.getter()
、property.setter()
、property.deleter()
を abstractmethodで使用できるようになりました()、このデコレータを冗長にします。組み込みの property()のサブクラスで、抽象プロパティを示します。
property()デコレータが抽象メソッドに適用されたときに抽象として正しく識別されるようになったため、この特殊なケースは非推奨になりました。
class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
上記の例では、読み取り専用プロパティを定義しています。 基礎となるメソッドの1つ以上を抽象として適切にマークすることにより、読み取り/書き込み抽象プロパティを定義することもできます。
class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...
一部のコンポーネントのみが抽象である場合、サブクラスに具象プロパティを作成するには、それらのコンポーネントのみを更新する必要があります。
class D(C): @C.x.setter def x(self, val): ...
abc モジュールは、次の機能も提供します。
- abc.get_cache_token()
現在の抽象基本クラスのキャッシュトークンを返します。
トークンは、仮想サブクラスの抽象基本クラスキャッシュの現在のバージョンを識別する不透明なオブジェクト(同等性テストをサポート)です。 トークンは、ABCで ABCMeta.register()を呼び出すたびに変更されます。
バージョン3.4の新機能。
脚注
- 1
- C ++プログラマーは、Pythonの仮想基本クラスの概念がC ++の概念と同じではないことに注意する必要があります。