Pythonは非常に柔軟な言語です。 この柔軟性の側面の1つは、メタプログラミングによって提供される可能性です。 抽象クラスとインターフェースは言語のコアでは表現されませんが、前者は標準のabcモジュールで実装され、後者はZopeプロジェクト(zope.interfacesモジュール)で実装されました。
両方を同時に使用することは意味がないため、各プログラマーは、アプリケーションの設計時に使用するツールを自分で決定する必要があります。
2抽象基本クラス(ab)
言語バージョン2.6以降、abcモジュールは標準ライブラリに含まれ、言語に抽象ベースクラス(以降ABK)が追加されます。
ABAでは、派生クラスでどのメソッドまたはプロパティを再定義する必要があるかを示しながら、クラスを定義できます。
abc import ABCMeta、abstractmethod、abstractpropertyから クラスMovable(): __metaclass __ = ABCMeta @abstractmethod def move(): 「」「オブジェクトを移動」「」 しゅう def速度(): 「」「オブジェクト速度」「」
したがって、コード内で特定の速度で移動できるオブジェクトを使用する場合は、Movableクラスを基本クラスの1つとして使用する必要があります。
オブジェクトの必要なメソッドと属性の存在は、クラスの祖先間のABAの存在によって保証されるようになりました。
クラスCar(Movable): def __init__: self.speed = 10 self.x = 0 def move(自己): self.c + = self.speed def速度(自己): self.speedを返す issubclassのアサート(Car、Movable) インスタンスのアサート(Car()、Movable)
ABAの概念はクラス継承の階層にうまく適合し、使いやすく、abcモジュールのソースコードを見ると実装は非常に簡単であることがわかります。 抽象クラスは標準のコレクションと数値モジュールで使用され、定義に必要なカスタムメソッドを設定します
後継クラス。
ABAの使用に関する詳細と考慮事項は、PEP 3119に記載されています。
( http://www.python.org/dev/peps/pep-3119/ )。
3インターフェース(zope.interfaces)
Zope3で作業中のZopeプロジェクトの実装は、コンポーネントアーキテクチャに焦点を合わせることにしました。 フレームワークは、ほぼ独立したコンポーネントのセットに変わりました。 接着剤接続コンポーネント-それらに基づくインターフェースとアダプター。
zope.interfacesモジュールは、この作業の結果です。
最も単純な場合、インターフェースの使用はABAの例に似ています:
インポートzope.interface クラスIVehicle(zope.interface.Interface): 「」「動くもの」「」 speed = zope.interface.Attribute( "" "移動速度" "") def move(): 「」「一歩踏み出す」「」 クラスCar(オブジェクト): zope.interface.implements(IVehicle) def __init__: self.speed = 1 self.location = 1 def move(自己): self.location = self.speed * 1 「移動しました!」 assert IVehicle.implementedBy(車) IVehicle.providedBy(車())をアサートします
インターフェイスは、オブジェクトが持つべき属性とメソッドを宣言的に示します。 さらに、クラスはインターフェイスを実装し、クラスオブジェクトが提供します。 これらの概念の違いに注意する必要があります!
インターフェイスの「実装」とは、「生成された」エンティティのみが必要なプロパティを持つことを意味します。 インターフェイスの「プロビジョニング」は、評価されるエンティティの特定の機能を示します。 したがって、Pythonでは、クラスはインターフェースを実装および提供できます。
実際、実装宣言(IVehicle)は規則です。 与えられたクラスとそのオブジェクトがまさにこのように振る舞うという約束。 実際のチェックは行われません
クラスIVehicle(zope.interface.Interface): 「」「動くもの」「」 speed = zope.interface.Attribute( "" "移動速度" "") def move(): 「」「一歩踏み出す」「」 クラスCar(オブジェクト): zope.interface.implements(IVehicle) assert IVehicle.implementedBy(車) IVehicle.providedBy(車())をアサートします
もっとも単純な場合、インターフェースはコードを複雑にするだけであることがわかります。
Zopeのコンポーネントアーキテクチャには、アダプタというもう1つの重要な概念が含まれています。 一般的に、これは異なるメソッドと属性のセットが必要な場所で使用するために1つのクラスを修正する単純な設計パターンです。 だから
4つのアダプター
Zopeコンポーネントアーキテクチャの包括的なガイドの例を大幅に簡素化して検討してください。
GuestとDeskというクラスがいくつかあるとします。 それらへのインターフェースと、Guestインターフェースを実装するクラスを定義します。
インポートzope.interface zope.interface import implementsから zope.componentインポートから適応、getGlobalSiteManager クラスIDesk(zope.interface.Interface): defレジスタ(): 「人を登録する」 クラスIGuest(zope.interface.Interface): name = zope.interface.Attribute( "" "Person`s name" "") クラスGuest(オブジェクト): 実装(IGuest) def __init __(自己、名前): self.name = name
アダプターは、名前のリストに登録することにより、匿名ゲストを考慮する必要があります。
クラスGuestToDeskAdapter(オブジェクト): 適応(イグゲスト) 実装(IDesk) def __init __(自己、ゲスト): self.guest =ゲスト def register(self): guest_name_db.append(self.guest.name)
インターフェース間でアダプターを追跡するレジストリーがあります。 そのおかげで、インターフェイスクラスの呼び出しに適応可能なオブジェクトを渡すことで、アダプターを取得できます。 アダプタが登録されていない場合、2番目のインターフェイス引数が返されます。
guest = Guest( "Ivan") アダプター= IDesk(ゲスト、代替=なし) プリントアダプター >>>>見つかりません gsm = getGlobalSiteManager() gsm.registerAdapter(GuestToDeskAdapter) アダプター= IDesk(ゲスト、代替=「見つかりません」) プリントアダプター >>>> __ main __。0xb7beb64cのGuestToDeskAdapterオブジェクト>
このようなインフラストラクチャを使用して、コードをコンポーネントとそのバインディングに分割すると便利です。
Zope自体の他にこのアプローチを使用する最も顕著な例の1つは、ツイストネットワークフレームワークです。このフレームワークでは、かなりの量のアーキテクチャがzope.interfacesからのインターフェースに依存しています。
5結論
よく見ると、インターフェースと抽象基本クラスは2つの異なるものであることがわかりました。
抽象クラスは、基本的に必要なインターフェイスパーツを厳密に定義します。 オブジェクトが抽象クラスインターフェイスに準拠しているかどうかの確認は、組み込みのisinstance関数を使用して確認されます。 クラス-issubclass。 抽象基本クラスは、基本クラスまたはミックスインとして階層に含める必要があります。
マイナスはissubclassのセマンティクスであり、通常のクラス(それらの継承階層)と交差するisinstanceチェックです。 ABAには追加の抽象化は組み込まれていません。
インターフェイスは宣言的な本質であり、フレームワークを配置しません。 クラスが実装すること、およびそのオブジェクトがインターフェースを提供することだけが述べられています。 意味的には、implementedBy、providedByのステートメントがより正確です。 このような単純なベースでは、アダプターやその他の派生エンティティを使用してコンポーネントアーキテクチャを構築すると便利です。これは、大規模なZopeおよびTwistedフレームワークが行うことです。
両方のツールの使用は、比較的大きなOOPシステム(フレームワークとライブラリ)を構築して使用する場合にのみ意味があることを理解する必要があります。小さなプログラムでは、コードを不必要に抽象化して混乱させるだけです。