Source

pymotw-ja / PyMOTW / abc / index.rst

abc -- 抽象基底クラス

目的:コードをチェックする API のために抽象基底クラスの使用、定義する
Python バージョン:2.6

なぜ抽象基底クラスを使用するのか?

抽象基底クラス(ABC)は特定メソッドをチェックする個別の hasattr() よりも厳密なチェックのためのインタフェースです。抽象基底クラスを定義することでサブクラスセットのための共通 API を定義することができます。この機能はアプリケーションに対するプラグインのような、サードパーティが実装を提供する状況でかなり便利です。さらに、同時に頭の中で全クラスを把握することが難しい、もしくは不可能な、大規模なチーム又はコードベースで開発することもできます。

どのように ABC を用いて開発するか

:mod:`abc` は抽象的な基底クラスのメソッドをマークしてから、抽象基底クラスの実装として具象クラスを登録します。コードが特定 API を要求するなら、抽象クラスに対するオブジェクトをチェックするために issubclass()isinstance() を使用することができます。

データの保存や読み込みのためのプラグインセットの API を表すために抽象基底クラスを定義してみましょう。

具象クラスを登録する

そのクラスを ABC で登録するか、ABC から直接サブクラス化するかといった抽象的なモノを実装する具象クラスを指し示す方法が2つあります。

この例の RegisteredImplementationPluginBase から派生しませんが PluginBase API の実装として登録されます。

サブクラス化による実装

その基底クラスから直接サブクラス化することで明示的にその具象クラスを登録する必要はありません。

このケースでは、通常の Python のクラス管理が抽象クラス PluginBase を実装する SubclassImplementation を認識します。

直接サブクラス化することの副作用は、抽象クラスから派生したクラスリストの基底クラスを調べることでプラグインの全ての実装を見つけられることです(これは ABC の機能ではなく、全てのクラスがこのように動作します)。

abc_register がインポートされたとしても、実際にはその基底クラスから派生していないので RegisteredImplementation がサブクラスのリストに存在しないことに気付いてください。

Dr. André Roberge は動的にディレクトリ内の全モジュールをインポートしてから実装クラスを見つけるためにサブクラスリストを探することで、プラグインを発見するためにこの機能を使用することを 説明しました

不完全な実装

抽象基底クラスから直接サブクラス化することの他の利点は API の抽象的な部分を完全に実装しない限りサブクラスはインスタンス化されないということです。これは中途半端な実装で実行時に予測されないエラーを発生させないようにします。

ABC の具象メソッド

具象クラスは抽象メソッドの実装を提供しなければならないですが、抽象基底クラスが super() を通して実行される実装を提供することもできます。これは基底クラスに抽象メソッドの実装を配置することで共通ロジックを再利用させますが、(潜在的に)カスタムロジックでオーバーライドされたメソッドを提供することをサブクラスに強制します。

ABCWithConcreteImplementation は抽象基底クラスなので、そのクラスを直接インスタンス化することはできません。サブクラスは retrieve_values() をオーバーライドして 提供しなければなりません 。そして、このケースでは具象クラスが入力データを返す前にメッセージを表示します。

抽象プロパティ

API 仕様がメソッドに加えて属性を含むなら @abstractproperty で、そのようなメソッドを定義することで具象クラスに属性を要求することができます。

このサンプルの Base クラスは抽象プロパティのゲッタメソッドしか持たないのでインスタンス化できません。

抽象的な read/write プロパティを定義することもできます。

具象プロパティは抽象プロパティと同じ方法で定義されなければならないことに注意してください。 PartialImplementation の read/write プロパティを 'Read-only' でオーバーライドしようとしても動作しません。

抽象的な read/write プロパティを扱うデコレータ構文を使用するために value を get/set するメソッドは同じ名前にすべきです。

BaseImplementation クラスの2つのメソッドは引数は違いますが value() という名前で定義していることに注意してください。

コレクション型

:mod:`collections` モジュールはコンテナ(とコンテナにできる)型に関連する複数の抽象基底クラスを定義します。

  • Container
  • Sized

イテレータとシーケンスクラス:

  • Iterable
  • Iterator
  • Sequence
  • MutableSequence

ユニークな値:

  • Hashable
  • Set
  • MutableSet

マッピング:

  • Mapping
  • MutableMapping
  • MappingView
  • KeysView
  • ItemsView
  • ValuesView

その他:

  • Callable

抽象基底クラスの現実世界の詳細なサンプルとして提供することに加えて Python のビルトイン型は :mod:`collections` をインポートするとき、これらのクラスに対して自動的に登録されます。これは必要とする API をこれらのクラスがサポートすることを保証して、コードのパラメータをチェックするために isinstance() を安全に使用できることを意味します。さらに、これらのクラスの多くは内部の具象的な実装を提供してオーバーライドされた数個のメソッドのみを必要とするので、その基底クラスは独自のコレクション型を定義するために使用されます。詳細はコレクションモジュールの標準ライブラリドキュメントを参照してください。