Zopeインターフェースの目的?
-
22-09-2019 - |
質問
私はコード内で Zope インターフェースを使い始めましたが、現時点では、それらは実際には単なるドキュメントです。これらを使用して、クラスが所有する必要がある属性を指定し、それらを適切なクラスに明示的に実装し、必要な場合にはそれらを明示的にチェックします。これはこれで問題ありませんが、クラスがインターフェイスを実装していると述べたことを単に検証するのではなく、クラスがインターフェイスを実装していることを実際に検証するなど、可能であればさらに多くのことを行ってもらいたいと思います。私は zope wiki を何度か読みましたが、現在私が行っていること以上にインターフェイスを使用する方法はまだ見つかりません。そこで、私の質問は、これらのインターフェイスを他に何に使用できるのか、さらにどのように使用できるのかということです。
解決
あなたは、実際にテストをすることができます。
:あなたは(あなたが通常あなたのテストでそれを使用する)verify
モジュールを使用することができることについては
>>> from zope.interface import Interface, Attribute, implements
>>> class IFoo(Interface):
... x = Attribute("The X attribute")
... y = Attribute("The Y attribute")
>>> class Foo(object):
... implements(IFoo)
... x = 1
... def __init__(self):
... self.y = 2
>>> from zope.interface.verify import verifyObject
>>> verifyObject(IFoo, Foo())
True
>>> from zope.interface.verify import verifyClass
>>> verifyClass(IFoo, Foo)
True
インターフェースも不変量を設定し、テストするために使用することができます。 あなたがここでより多くの情報を見つけることができます:
他のヒント
私の職場では、ZCA を使用できるようにインターフェイスを使用しています。 Zope コンポーネントのアーキテクチャ, 、これは、交換可能でプラグイン可能なコンポーネントを作成するためのフレームワーク全体です。 Interface
s.ZCA を使用することで、必ずしもソフトウェアをフォークしたり、クライアントごとの多数のビットでメイン ツリーを混乱させたりする必要がなく、クライアントごとのあらゆる種類のカスタマイズに対応できます。残念ながら、Zope wiki は非常に不完全であることがよくあります。ZCA の機能のほとんどについては、わかりやすく簡潔に説明されています。 ZCAのpypiページ.
使いません Interface
クラスが指定されたメソッドのすべてのメソッドを実装しているかどうかをチェックするなどの用途に使用します。 Interface
. 。理論的には、これは、インターフェイスに別のメソッドを追加するときに、そのインターフェイスを実装するすべてのクラスに新しいメソッドを追加したことを忘れていないことを確認するのに役立つ可能性があります。個人的には、新しいものを作成することを強く好みます Interface
古いものを修正しすぎます。古いものを変更する Interfaces
pypi や他の組織に放出された卵の中にそれらが含まれると、通常は非常に悪い考えになります。
用語についての簡単なメモ:クラス 埋め込む Interface
およびオブジェクト (クラスのインスタンス) 提供する Interface
s.を確認したい場合は、 Interface
, 、次のように書きます。 ISomething.implementedBy(SomeClass)
または ISomething.providedBy(some_object)
.
それでは、ZCA が役立つ例を見ていきましょう。ZCA を使用してブログをモジュール化して、ブログを書いているとしましょう。いただきます BlogPost
各投稿のオブジェクト。 IBlogPost
インターフェイス、すべてハンディダンディで定義されています my.blog
卵。ブログの設定も保存します BlogConfiguration
提供するオブジェクト IBlogConfiguration
. 。これを開始点として使用すると、必ずしも触れることなく新しい機能を実装できます。 my.blog
全然。
以下は、ベースを変更せずに ZCA を使用して実行できることの例のリストです。 my.blog
卵。当時はブログを実装していませんでしたが、私または私の同僚は実際のクライアント向けプロジェクトでこれらすべてのことを実行しました (そして、それらが役立つと感じました)。:) ここでのユースケースの中には、CSS ファイルの印刷など、他の手段でより適切に解決できるものもあります。
追加のビューの追加 (
BrowserView
s、通常はに登録されています ZCML とともにbrowser:page
ディレクティブ) を提供するすべてのオブジェクトにIBlogPost
. 。作ることができましたmy.blog.printable
卵。その卵は BrowserView を登録します。print
のためにIBlogPost
, 、ブログ投稿をレンダリングします。 Zopページテンプレート 適切に印刷される HTML を生成するように設計されています。それBrowserView
URL に表示されます/path/to/blogpost/@@print
.Zope のイベント サブスクリプション メカニズム。RSS フィードを公開したいと考えており、要求に応じて生成するのではなく、事前に生成したいとします。を作成できました
my.blog.rss
卵。その卵では、以下を提供するイベントのサブスクライバーを登録します。 IObjectModified (zope.lifecycleevent.interfaces.IObjectModified
)、提供するオブジェクトに対してIBlogPost
. 。そのサブスクライバは、提供するもので属性が変更されるたびに呼び出されます。IBlogPost
, これを使用して、ブログ投稿が表示されるすべての RSS フィードを更新できます。この場合は、あったほうがよいかもしれません。
IBlogPostModified
各イベントの最後に送信されるイベントBrowserView
ブログ投稿を変更するため、IObjectModified
属性が変更されるたびに 1 回送信されますが、パフォーマンスを考慮すると頻度が高すぎる可能性があります。アダプター。アダプタは、あるインターフェイスから別のインターフェイスに事実上「キャスト」されます。プログラミング言語マニア向け:Zope アダプターは、Python で「オープン」複数ディスパッチを実装します (「オープン」とは、「どの卵からでもケースを追加できる」という意味です)。より具体的なインターフェースの一致が、あまり具体的でない一致よりも優先されます (
Interface
クラスは互いのサブクラスにすることができ、これはまさに期待通りの動作をします。)アダプターを1つから
Interface
非常に優れた構文で呼び出すことができます。ISomething(object_to_adapt)
, 、または関数経由で検索できますzope.component.getAdapter
. 。複数のアダプターInterface
関数を介して検索する必要がありますzope.component.getMultiAdapter
, これは少し美しさが劣ります。特定のセットに対して複数のアダプターを使用できます。
Interface
s、文字列で区別name
アダプターの登録時に指定します。名前のデフォルトは、""
. 。例えば、BrowserView
は実際には、登録されているインターフェイスと HTTPRequest クラスが実装するインターフェイスから適応するアダプターです。調べることもできます 全て の 1 つのシーケンスから登録されたアダプターの数Interface
別のものにInterface
, を使用してzope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
, 、(名前、アダプター) ペアのシーケンスを返します。これは、プラグインが接続するためのフックを提供する非常に優れた方法として使用できます。すべてのブログの投稿と設定を 1 つの大きな XML ファイルとして保存したいとします。私は
my.blog.xmldump
を定義する卵IXMLSegment
, 、からアダプターを登録しますIBlogPost
にIXMLSegment
そしてアダプターはIBlogConfiguration
にIXMLSegment
. 。次のように書くことで、シリアル化したいオブジェクトに適したアダプターを呼び出すことができます。IXMLSegment(object_to_serialize)
.他のさまざまなものからさらにアダプターを追加することもできます
IXMLSegment
卵以外からmy.blog.xmldump
. 。ZCML には、egg がインストールされている場合に限り、特定のディレクティブを実行できる機能があります。これを使えばmy.blog.rss
からアダプターを登録しますIRSSFeed
にIXMLSegment
もしmy.blog.xmldump
作成せずにたまたまインストールされているmy.blog.rss
によるmy.blog.xmldump
.Viewlet
は小さいようなものですBrowserView
ページ内の特定の場所を「購読」できるということです。今は詳細をすべて思い出せませんが、これらはサイドバーに表示したいプラグインなどに非常に適しています。彼らがベースの Zope の一部なのか Plone の一部なのかは直接思い出せません。解決しようとしている問題に実際に本物の CMS が必要な場合を除き、Plone は使用しないことをお勧めします。Plone は大きくて複雑なソフトウェアであり、速度がやや遅い傾向があるためです。
実際には必ずしも必要ではありません
Viewlet
とにかく、それ以来BrowserView
TAL 式で 'object/@@some_browser_view' を使用するか、またはqueryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
, 、しかし、それにもかかわらず、それらはかなり素晴らしいです。マーカー
Interface
s.マーカーInterface
ですInterface
メソッドも属性も提供しません。マーカーを追加できますInterface
実行時に使用する任意のオブジェクトISomething.alsoProvidedBy
. 。これにより、たとえば、特定のオブジェクトでどのアダプタが使用されるか、およびどのアダプタが使用されるかを変更できます。BrowserView
s が定義されます。
これらの各例をすぐに実装できるほど詳しく説明していないことをお詫びします。ただし、それぞれの例をブログに投稿するのに 1 つほどかかります。
はZopeのインタフェースが互いに依存してはならないコードの二つの部品を分離するための有用な方法を提供することができる。
と言う我々はモジュールa.pyに挨拶を印刷する方法を知っているコンポーネントを持っています
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
やニーズがモジュールb.pyで挨拶印刷することをいくつかのコード:
を>>> Greeter().greet()
'Hello'
この配置は、それがコードアウトスワップするハードハンドルが(別のパッケージで配布されるかもしれない)接触b.pyずに挨拶することを行います。
:その代わりに、我々はIGreeterインタフェースを定義する第3のモジュールのc.pyを導入することができ>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
今、私たちはデカップルa.pyとb.py.にこれを使用することができます代わりにGreeterクラスをインスタンス化のため、b.pyは今IGreeterインタフェースを提供するユーティリティをお願いします。そしてa.pyは、Greeterクラスの実装を宣言します、そのインタフェースます:
(a.py)
>>> from zope.interface import implementer
>>> from zope.component import provideUtility
>>> from c import IGreeter
>>> @implementer(IGreeter)
... class Greeter(object):
... def greet(self):
... print 'Hello'
>>> provideUtility(Greeter(), IGreeter)
(b.py)
>>> from zope.component import getUtility
>>> from c import IGreeter
>>> greeter = getUtility(IGreeter)
>>> greeter.greet()
'Hello'
私は Zope インターフェースを使用したことがありませんが、 メタクラス, 、初期化時にインターフェイスに対してクラスのメンバーをチェックし、メソッドが実装されていない場合は実行時例外を発生させます。
Python には他の選択肢はありません。コードを検査する「コンパイル」ステップを設けるか、実行時にコードを動的に検査します。