# `abc` --- 抽象基底クラス

ソースコード: 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.abc` submodule 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.

このモジュールは、 抽象基底クラスを定義するためのメタクラス `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

  バージョン 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 のサブクラスと見なせるかどうかチェックします。これによって ABC のサブクラスと見なしたい全てのクラスについて `register()` を呼び出すことなく `issubclass` の振る舞いをさらにカスタマイズできます。 (このクラスメソッドは 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__()` の意味は、 `__iter__()` メソッドがクラスの(または `__mro__` でアクセスされる基底クラスの一つの) `__dict__` にある場合にもそのクラスが `MyIterable` だと見なされるということです。

  最後に、一番下の行は `Foo` を `__iter__()` メソッドを定義しないにもかかわらず `MyIterable` の仮想的サブクラスにします(`Foo` は古い様式の `__len__()` と `__getitem__()` を用いたイテレータプロトコルを使っています。)。これによって `Foo` のメソッドとして `get_iterator` が手に入るわけではないことに注意してください。それは別に提供されています。

`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)

  デスクリプタをABC 機構と協調させるために、デスクリプタは `__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`

  バージョン 3.2 で追加.

  バージョン 3.3 で非推奨: `classmethod` を `abstractmethod()` と一緒に使えるようになったため、このデコレータは冗長になりました。

  組み込みの `classmethod()` のサブクラスで、抽象クラスメソッドであることを示します。それ以外は `abstractmethod()` と同じです。

  この特殊ケースは `classmethod()` デコレータが抽象メソッドに適用された場合に抽象的だと正しく認識されるようになったため撤廃されます:

      class C(ABC):
          @classmethod
          @abstractmethod
          def my_abstract_classmethod(cls, arg):
              ...

`@``abc.``abstractstaticmethod`

  バージョン 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()` の呼び出しごとに、トークンは変更されます。

  バージョン 3.4 で追加.

`abc.``update_abstractmethods`(cls)

  A function to recalculate an abstract class's abstraction status. This function should be called if a class's abstract methods have been implemented or changed after it was created. Usually, this function should be called from within a class decorator.

  Returns cls, to allow usage as a class decorator.

  If cls is not an instance of `ABCMeta`, does nothing.

  注釈

  This function assumes that cls's superclasses are already updated. It does not update any subclasses.

  バージョン 3.10 で追加.

脚注

1

  C++ プログラマは Python の仮想的基底クラスの概念は C++ のものと同じではないということを銘記すべきです。