### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python v2.6.2 documentation »
- Python 標準ライブラリ »
- 28. Python ランタイムサービス »

# 28.7. `abc` — 抽象基底クラス

バージョン 2.6 で追加.

このモジュールは Python に PEP 3119 で概要が示された抽象基底クラス (abstract base class, ABC) を定義する基盤を提供します。 なぜこれが Python に付け加えられたかについてはその PEP を参照してください。 (ABC に基づいた数の型階層を扱った PEP 3141 と `numbers` モジュールも参照してください。)

`collections` モジュールには ABC から派生した具象クラスがいくつかあります。 これらから、もちろんですが、さらに派生させることもできます。また `collections` モジュールにはいくつかの ABC もあって、あるクラスやインスタンスが特定のインタフェースを提供しているかどうか、たとえばハッシュ可能かあるいはマッピングか、をテストできます。

このモジュールは以下のクラスを提供します:

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` を返す場合は、たとえ通常の意味でサブクラスであっても 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)

Footnotes

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

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python v2.6.2 documentation »
- Python 標準ライブラリ »
- 28. Python ランタイムサービス »