web-dev-qa-db-ja.com

Zopeインターフェースの目的は?

私は自分のコードでZopeインターフェースを使い始めましたが、今のところ、それらは実際には単なるドキュメントです。私はそれらを使用して、クラスが持つべき属性を指定し、それらを適切なクラスに明示的に実装し、期待する場所で明示的にチェックします。これは問題ありませんが、クラスがインターフェイスを実装していると言ったことを確認するだけでなく、クラスがインターフェイスを実装していることを実際に確認するなど、可能であればもっと多くのことをしてもらいたいと思います。私はzopewikiを数回読んだことがありますが、それでも私が現在行っていることよりもはるかに多くのインターフェースの使用法を見ることができません。ですから、私の質問は、これらのインターフェースを他に何に使用できるのか、そしてそれらをどのように使用するのかということです。

34
Nikwin

オブジェクトまたはクラスがインターフェースを実装しているかどうかを実際にテストできます。そのためには、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

インターフェイスは、不変条件の設定とテストにも使用できます。あなたはここでより多くの情報を見つけることができます:

http://www.muthukadan.net/docs/zca.html#interfaces

23
Ruslan Spivak

私が働いているところでは、ZCA、またはInterfacesを使用してスワップ可能およびプラグ可能なコンポーネントを作成するためのフレームワーク全体である Zope Component Architecture を使用できるようにインターフェイスを使用します。 ZCAを使用することで、ソフトウェアをフォークしたり、クライアントごとの多くのビットをすべてメインツリーで混乱させたりすることなく、あらゆる種類のクライアントごとのカスタマイズに対応できます。残念ながら、Zopewikiはかなり不完全なことがよくあります。その ZCAのpypiページ にZCAの機能のほとんどの良いが簡潔な説明があります。

クラスが特定のInterfaceのすべてのメソッドを実装していることを確認するなどの目的でInterfacesを使用することはありません。理論的には、これは、インターフェイスに別のメソッドを追加するときに、インターフェイスを実装するすべてのクラスに新しいメソッドを追加することを覚えているかどうかを確認するのに役立つ場合があります。個人的には、古いものを変更するよりも、新しいInterfaceを作成することを強く好みます。古いInterfacesを変更することは、pypiまたは組織の他の部分にリリースされた卵に含まれると、通常は非常に悪い考えです。

用語に関する簡単なメモ:クラス実装Interfaces、およびオブジェクト(クラスのインスタンス)provideInterfaces。 Interfaceを確認する場合は、ISomething.implementedBy(SomeClass)またはISomething.providedBy(some_object)と記述します。

したがって、ZCAが役立つ場所の例に至るまで。 ZCAを使用してブログをモジュール化して、ブログを書いているとしましょう。投稿ごとにBlogPostオブジェクトがあり、これはIBlogPostインターフェイスを提供します。これらはすべて、便利な_my.blog_ Eggで定義されています。また、ブログの構成をBlogConfigurationを提供するIBlogConfigurationオブジェクトに保存します。これを出発点として使用すると、必ずしも_my.blog_に触れることなく、新しい機能を実装できます。

以下は、ベース_my.blog_ Eggを変更せずにZCAを使用して実行できることの例のリストです。当時はブログを実装していませんでしたが、私または私の同僚は、実際のクライアント向けプロジェクトでこれらすべてのことを実行しました(そしてそれらが有用であることがわかりました)。 :)ここでのユースケースのいくつかは、CSSファイルの印刷などの他の手段によってよりよく解決される可能性があります。

  1. BrowserViewを提供するすべてのオブジェクトに追加のビュー(IBlogPosts、通常は [〜#〜] zcml [〜#〜] に_browser:page_ディレクティブで登録)を追加します。 _my.blog.printable_の卵を作ることができました。そのEggはprintIBlogPostと呼ばれるBrowserViewを登録します。これは、うまく印刷されるHTMLを生成するように設計された Zope Page Template を介してブログ投稿をレンダリングします。そのBrowserViewはURL _/path/to/blogpost/@@print_に表示されます。

  2. Zopeのイベントサブスクリプションメカニズム。 RSSフィードを公開したいが、要求に応じてではなく事前に生成したいとします。 _my.blog.rss_エッグを作成できます。そのEggで、IBlogPostを提供するオブジェクトで、 IObjectModified (_zope.lifecycleevent.interfaces.IObjectModified_)を提供するイベントのサブスクライバーを登録します。そのサブスクライバーは、IBlogPostを提供するものの属性が変更されるたびに呼び出され、ブログ投稿が表示されるすべてのRSSフィードを更新するために使用できます。

    この場合、ブログ投稿を変更する各IBlogPostModifiedsの最後に送信されるBrowserViewイベントがある方がよい場合があります。これは、IObjectModifiedが属性の変更ごとに1回送信されるためです。これは、パフォーマンスのために頻繁に行われる可能性があります。

  3. アダプター。アダプターは、あるインターフェースから別のインターフェースに効果的に「キャスト」されます。プログラミング言語オタクの場合:Zopeアダプターは、Python(「open」とは「任意のEggからさらにケースを追加できる」という意味)で「open」多重ディスパッチを実装し、より具体的なインターフェースを一致させますあまり具体的でない一致よりも優先されます(Interfaceクラスは相互のサブクラスになる可能性があり、これはまさにあなたが望むことを実行します。)

    1つのInterfaceからのアダプターは、非常に優れた構文ISomething(object_to_adapt)で呼び出すか、関数_zope.component.getAdapter_を介して検索できます。複数のInterfacesからのアダプターは、関数_zope.component.getMultiAdapter_を介して検索する必要がありますが、これは少しきれいではありません。

    Interfacesの特定のセットに対して、アダプターの登録時に指定する文字列nameによって区別される、複数のアダプターを持つことができます。名前のデフォルトは_""_です。たとえば、BrowserViewsは、実際には、それらが登録されているインターフェースとHTTPRequestクラスが実装するインターフェースから適応するアダプターです。 zope.component.getAdapters( (IAdaptFrom,), IAdaptTo )を使用して、Interfacesの1つのシーケンスから別のInterfaceに登録されているアダプターのすべてallを検索することもできます。 (名前、アダプター)ペアのシーケンス。これは、プラグインが接続するためのフックを提供するための非常に優れた方法として使用できます。

    ブログのすべての投稿と構成を1つの大きなXMLファイルとして保存したいとします。 IXMLSegmentを定義する_my.blog.xmldump_ Eggを作成し、アダプターをIBlogPostからIXMLSegmentに、アダプターをIBlogConfigurationからIXMLSegmentに登録します。 IXMLSegment(object_to_serialize)と書くことで、シリアル化するオブジェクトに適したアダプターを呼び出すことができます。

    _my.blog.xmldump_以外の卵からIXMLSegmentに、他のさまざまなものからさらにアダプターを追加することもできます。 ZCMLには、Eggがインストールされている場合にのみ、特定のディレクティブを実行できる機能があります。これを使用して、_my.blog.rss_を_my.blog.xmldump_に依存させることなく、_my.blog.rss_がたまたまインストールされた場合にIRSSFeedからIXMLSegmentへのアダプターを_my.blog.xmldump_に登録させることができます。

  4. Viewletsは、ページ内の特定の場所に「サブスクライブ」させることができる小さなBrowserViewsのようなものです。今のところすべての詳細を思い出せませんが、これらはサイドバーに表示したいプラグインのようなものに非常に適しています。

    彼らがベースのZopeの一部なのかPloneの一部なのか、私はすぐに思い出せません。 Ploneは大きくて複雑なソフトウェアであり、少し遅い傾向があるため、解決しようとしている問題が実際に実際のCMSを必要としない限り、Ploneの使用はお勧めしません。

    Viewletsは、TAL式で 'object/@@ some_browser_view'を使用するか、queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )を使用して相互に呼び出すことができるため、実際には必ずしもBrowserViewsは必要ありませんが、それでもかなり優れています。

  5. マーカーInterfaces。マーカーInterfaceは、メソッドも属性も提供しないInterfaceです。 _ISomething.alsoProvidedBy_を使用して、実行時に任意のオブジェクトにマーカーInterfaceを追加できます。これにより、たとえば、特定のオブジェクトで使用されるアダプタと、そのオブジェクトで定義されるBrowserViewsを変更できます。

これらの各例をすぐに実装するのに十分な詳細を説明していないことをお詫びしますが、それぞれ約ブログ投稿が必要です。

52
Richard Barrell

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を分離できます。グリータークラスをインスタンス化する代わりに、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'
19
David Glick

私はZopeインターフェースを使用したことがありませんが、 metaclass を作成することを検討してください。これは、初期化時にクラスのメンバーをインターフェースと照合し、メソッドが実装されていない場合はランタイム例外を発生させます。

Pythonを使用すると、他のオプションはありません。コードを検査する「コンパイル」ステップを使用するか、実行時に動的に検査します。

2
Daniel Naab