私は自分のコードでZopeインターフェースを使い始めましたが、今のところ、それらは実際には単なるドキュメントです。私はそれらを使用して、クラスが持つべき属性を指定し、それらを適切なクラスに明示的に実装し、期待する場所でそれらを明示的にチェックします。これは問題ありませんが、クラスがインターフェイスを実装していると言ったことを確認するだけでなく、クラスがインターフェイスを実装していることを実際に確認するなど、可能であればもっと多くのことをしてもらいたいと思います。私はzopewikiを数回読んだことがありますが、それでも私が現在行っていることよりもはるかに多くのインターフェースの使用法を見ることができません。ですから、私の質問は、これらのインターフェースを他に何に使用できるのか、そしてどのようにそれらをより多く使用するのかということです。
4 に答える
私が働いている場所では、インターフェイスを使用してZCA、またはsを使用してスワップおよびプラグ可能なコンポーネントを作成するためのフレームワーク全体であるZopeコンポーネントアーキテクチャInterface
を使用できるようにしています。ZCAを使用することで、ソフトウェアをフォークしたり、クライアントごとの多くのビットをすべてメインツリーで混乱させたりすることなく、あらゆる種類のクライアントごとのカスタマイズに対応できます。残念ながら、Zopewikiは非常に不完全なことがよくあります。ZCAのpypiページには、ZCAのほとんどの機能についての簡潔な説明があります。
Interface
クラスが特定ののすべてのメソッドを実装していることを確認するなどの目的でsを使用することはありませんInterface
。理論的には、これは、インターフェイスに別のメソッドを追加するときに、インターフェイスを実装するすべてのクラスに新しいメソッドを追加したことを覚えているかどうかを確認するのに役立つ場合があります。個人的にはInterface
、古いものを変更するよりも新しいものを作成することを強く好みます。古いものを変更Interfaces
することは、pypiまたは組織の他の部分にリリースされた卵に含まれると、通常は非常に悪い考えです。
用語に関する簡単な注意:クラスはsを実装 Interface
し、オブジェクト(クラスのインスタンス)はsを提供します Interface
。をチェックしたい場合は、またはInterface
を記述します。ISomething.implementedBy(SomeClass)
ISomething.providedBy(some_object)
したがって、ZCAが役立つ場所の例に至るまで。ZCAを使用してブログをモジュール化してブログを書いているとしましょう。BlogPost
投稿ごとにオブジェクトがあり、インターフェースを提供しますIBlogPost
。これらはすべて、便利なダンディmy.blog
エッグで定義されています。BlogConfiguration
また、ブログの構成をを提供するオブジェクトに保存しますIBlogConfiguration
。これを出発点として、必ずしも何も触れなくても新しい機能を実装できますmy.blog
。
my.blog
以下は、ベースエッグを変更せずにZCAを使用して実行できることの例のリストです。当時はブログを実装していませんでしたが、私または私の同僚は、実際のクライアント向けプロジェクトでこれらすべてのことを実行しました(そしてそれらが有用であることがわかりました)。:)ここでのユースケースのいくつかは、CSSファイルの印刷などの他の手段によってよりよく解決される可能性があります。
を提供するすべてのオブジェクトに追加のビュー(
BrowserView
s、通常はディレクティブを使用してZCMLに登録されます)を追加します。卵を作ることができました。その卵は、必要なBrowserViewを登録します。これは、うまく印刷されるHTMLを生成するように設計されたZopeページテンプレートを介してブログ投稿をレンダリングします。その後、 URLに表示されます。browser:page
IBlogPost
my.blog.printable
print
IBlogPost
BrowserView
/path/to/blogpost/@@print
Zopeのイベントサブスクリプションメカニズム。RSSフィードを公開したいのですが、要求に応じてではなく、事前に生成したいとします。
my.blog.rss
卵を作ることができました。その卵では、を 提供するオブジェクトで、 IObjectModified(zope.lifecycleevent.interfaces.IObjectModified
)を提供するイベントのサブスクライバーを登録しますIBlogPost
。そのサブスクライバーは、提供するものの属性が変更されるたびに呼び出されIBlogPost
、ブログ投稿が表示されるすべてのRSSフィードを更新するために使用できます。この場合、ブログの投稿を変更する
IBlogPostModified
各の最後にイベントを送信する方がよい場合があります。これは、属性が変更されるたびに1回送信されるためです。これは、パフォーマンスのために頻繁に行われる可能性があります。BrowserView
IObjectModified
アダプター。アダプタは、あるインターフェイスから別のインターフェイスに効果的に「キャスト」されます。プログラミング言語オタクの場合:ZopeアダプターはPythonで「オープン」多重ディスパッチを実装します(「オープン」とは「任意の卵からより多くのケースを追加できる」という意味です)。より具体的なインターフェースの一致は、より具体的でない一致(
Interface
クラス)よりも優先されます。互いにサブクラスにすることができ、これはあなたが望むことを正確に実行します。)1つのアダプタは
Interface
、非常に優れた構文で呼び出すことがISomething(object_to_adapt)
できます。または、関数を介して検索できますzope.component.getAdapter
。複数のアダプタからのアダプタInterface
は、関数を介して検索する必要がありますがzope.component.getMultiAdapter
、これは少しきれいではありません。アダプターを登録するときに指定
Interface
する文字列によって区別される、特定のsのセットに対して複数のアダプターを持つことができます。name
名前のデフォルトは""
。です。たとえば、BrowserView
sは実際には、登録されているインターフェイスとHTTPRequestクラスが実装するインターフェイスから適応するアダプタです。を使用して、 sの1つのシーケンスから別のシーケンスに登録されているすべてのアダプターを検索することもできます。これは、(名前、アダプター)ペアのシーケンスを返します。これは、プラグインが接続するためのフックを提供するための非常に優れた方法として使用できます。Interface
Interface
zope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
ブログのすべての投稿と構成を1つの大きなXMLファイルとして保存したいとします。
my.blog.xmldump
を定義するeggを作成し、からへのアダプターとからへ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
sは、ページ内の特定の場所に「サブスクライブ」することができる小さなsのようなものです。今のところすべての詳細を思い出せませんが、これらはサイドバーに表示したいプラグインのようなものに非常に適しています。彼らがベースのZopeの一部なのかPloneの一部なのか、私は手に負えないことを思い出せません。Ploneは大きくて複雑なソフトウェアであり、少し遅い傾向があるため、解決しようとしている問題が実際に実際のCMSを必要としない限り、Ploneの使用はお勧めしません。
Viewlet
とにかく実際にsが必要なわけではありません。これは、BrowserView
sがTAL式で'object / @@ some_browser_view'を使用するか、を使用して相互に呼び出すことができるqueryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
ためです。マーカー
Interface
_ マーカーInterface
は、Interface
メソッドや属性を提供しないマーカーです。Interface
を使用して、実行時に任意のオブジェクトにマーカーを追加できますISomething.alsoProvidedBy
。これにより、たとえば、特定BrowserView
のオブジェクトで使用されるアダプターと、そのオブジェクトで定義されるアダプターを変更できます。
これらの各例をすぐに実装できるほど詳細に説明していないことをお詫びしますが、それぞれ約ブログ投稿が必要になります。
オブジェクトまたはクラスがインターフェースを実装しているかどうかを実際にテストできます。そのために、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
インターフェイスは、不変条件の設定とテストにも使用できます。あなたはここでより多くの情報を見つけることができます:
Zopeインターフェースは、相互に依存してはならない2つのコードを分離するための便利な方法を提供します。
モジュール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では、他のオプションはありません。コードを検査する「コンパイル」ステップを実行するか、実行時に動的に検査します。