Zweck der Zope-Schnittstellen?
-
22-09-2019 - |
Frage
Ich habe mit Zope Schnittstellen in meinem Code gestartet und ab sofort, sie sind wirklich nur Dokumentation. Ich benutze sie, um anzugeben, was die Klasse Attribute besitzen sollte, ausdrücklich in den entsprechenden Klassen implementieren und für sie explizit prüfen, wo ich zu erwarten. Das ist in Ordnung, aber ich mag sie mehr, wenn möglich zu tun, wie eigentlich die Klasse überprüfen, ob die Schnittstelle implementiert hat, anstatt nur die Überprüfung, dass ich gesagt habe, dass die Klasse implementiert die Schnittstelle. Ich habe das Zope Wiki ein paar Mal gelesen, aber immer noch nicht viel mehr Einsatz für Schnittstellen als sehen, was ich derzeit tue. Also, meine Frage ist, was sonst kann man diese Schnittstellen verwenden, weil und wie verwenden Sie sie für mehr.
Lösung
Sie können testen, tatsächlich, wenn Ihr Objekt oder Klasse implementiert Ihre Schnittstelle.
Dafür Sie verify
Modul verwenden können (Sie es normalerweise in Ihren Tests verwenden würde):
>>> 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
Schnittstellen kann auch zur Einstellung und Prüfung Invarianten verwendet werden. Sie können mehr Informationen finden Sie hier:
Andere Tipps
Wo ich arbeite, verwenden wir Schnittstellen, so dass wir ZCA verwenden können, oder die Zope Component Architecture , die für die Herstellung von Komponenten, die swappable und steckbare mit Interface
s ein ganzen Rahmen ist. Wir verwenden ZCA so, dass wir mit allen Arten von pro-Client-Anpassungen ohne unbedingt unsere Software gabeln oder haben all die vielen pro-Client-Bits vermasselt den Hauptbaum bewältigen kann. Der Zope Wiki ist oft sehr unvollständig, leider. Es gibt eine gute-but-lapidare Erklärung der meisten ZCA-Funktionen auf ihren ZCA der pypi .
Ich habe nicht Interface
s für etwas verwenden wie die Überprüfung, dass eine Klasse implementiert alle Methoden für einen bestimmten Interface
. In der Theorie, die vielleicht nützlich sein, wenn Sie eine andere Methode für eine Schnittstelle hinzufügen, um zu überprüfen, dass Sie die neue Methode alle Klassen hinzuzufügen habe daran erinnert, dass die Schnittstelle implementieren. Persönlich bevorzuge ich nachdrücklich empfohlen, einen neuen Interface
über Modifizieren eines alten zu erstellen. alt Interfaces
Modifizierung ist in der Regel eine sehr schlechte Idee, wenn sie in den Eiern sind, den pypi oder an den Rest Ihrer Organisation veröffentlicht wurde.
Eine kurze Anmerkung zur Terminologie: Klassen implementieren Interface
s und Objekte (Instanzen von Klassen) bietet Interface
s. Wenn Sie möchten, für einen Interface
überprüfen, würden Sie entweder schreiben oder ISomething.implementedBy(SomeClass)
ISomething.providedBy(some_object)
.
Also, bis auf Beispiele, wo ZCA ist nützlich. Nehmen wir an, dass wir ein Blog schreiben, die ZCA mit ihm modular zu machen. Wir werden für jede Stelle einen BlogPost
Gegenstand haben, die eine IBlogPost
Schnittstelle zur Verfügung stellt, die alle in unserem Handy-Dandy my.blog
Ei definiert. Wir speichern auch die Konfiguration des Blog in BlogConfiguration
Objekte, die IBlogConfiguration
liefern. Mit diesem als Ausgangspunkt, können wir neue Funktionen implementieren, ohne notwendigerweise my.blog
überhaupt zu berühren.
Im Folgenden ist eine Liste der Beispiele für Dinge, die wir durch die Verwendung ZCA tun können, ohne die Basis my.blog
Ei ändern zu müssen. Ich oder meine Mitarbeiter haben all diese Dinge getan (und fand sie nützlich) auf real für Client-Projekte, auch wenn wir nicht wurden Blogs zum Zeitpunkt der Umsetzung. :) Hier sind einige der Anwendungsfälle besser mit anderen Mitteln, wie beispielsweise eine Druck CSS-Datei gelöst werden könnten.
-
Hinzufügen von zusätzlichen Ansichten (
BrowserView
s, registriert in der Regel in ZCML mit derbrowser:page
-Richtlinie) auf alle Objekte, dieIBlogPost
bieten. Ich könnte einmy.blog.printable
Ei machen. Das Ei würde eine BrowserView genanntprint
fürIBlogPost
registrieren, die die Blog-Post über ein Zope Page Template produziert HTML entwickelt, den Druck schön. DieBrowserView
würde dann unter der URL/path/to/blogpost/@@print
erscheinen. -
Die Veranstaltung Abonnement-Mechanismus in Zope. Sagen wir, ich möchte RSS-Feeds veröffentlichen, und ich möchte, dass sie im Voraus erzeugen, anstatt auf Anfrage. Ich könnte ein
my.blog.rss
Ei erstellen. In diesem Ei, würde ich einen Teilnehmer für Veranstaltungen registrieren, die IObjectModified bieten (zope.lifecycleevent.interfaces.IObjectModified
), auf Objekte, dieIBlogPost
liefern. Das Teilnehmer würde jedes Mal, wenn ein Attribut geändert auf allem, was die BereitstellungIBlogPost
aufgerufen werden, und ich kann es alle der RSS-Feeds aktualisieren verwenden, dass die Blog-Post erscheint in sollte.In diesem Fall könnte es besser sein, ein
IBlogPostModified
Ereignis zu haben, die am Ende jeder derBrowserView
s dass modify Blog-Beiträge gesendet wird, daIObjectModified
bekommen sent einmal auf jedes einzelne Attribut ändern -., die für die Leistung willen zu oft sein könnte -
Adapter. Adapter sind effektiv „casts“ von einer Schnittstelle zur anderen. Für die Programmierung Sprache Geeks: Zope Adapter „offen“ Multiple-Versand in Python implementieren (durch „offene“ meine ich „Sie mehr Fälle von jedem Ei hinzufügen können“), mit mehr spezifischen Schnittstelle Streichhölzer nehmen Vorrang vor weniger spezifischen Spielen (
Interface
Klassen können Unterklassen sein ein anderes, und das genau das tut, was hoffen, dass Sie würde es tun würde.)Adapter von einer
Interface
kann mit einer sehr schönen Syntax,ISomething(object_to_adapt)
genannt werden, oder es kann über die Funktionzope.component.getAdapter
nachgeschlagen werden. Adapter von mehrerenInterface
s werden müssen über die Funktionzope.component.getMultiAdapter
nachgeschlagen, was ziemlich leicht weniger ist.Sie können mehr als einen Adapter für einen bestimmten Satz von
Interface
s, durch eine Schnurname
differenzierte, dass Sie bei der Registrierung der Adapter. Der Name standardmäßig""
. Zum BeispielBrowserView
s sind tatsächlich Adapter, die von der Schnittstelle anzupassen, dass sie sich auf und eine Schnittstelle, dass die Httprequest Klasse implementiert angemeldet sind. Sie können nachschlagen auch alle der Adapter, die von einer Sequenz vonInterface
s an einen anderenInterface
registriert sind, unter Verwendung vonzope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
, die eine Folge von (Name, Adapter) Paare zurück. Dies kann als eine sehr schöne Art und Weise verwendet werden, Haken für Plugins zur Verfügung zu stellen, sich heften sich an.Say Ich wollte alle meiner Blog-Posts und Konfiguration als eine große XML-Datei speichern. Ich schaffe eine
my.blog.xmldump
Ei, das eineIXMLSegment
definiert und registriert einen Adapter vonIBlogPost
zuIXMLSegment
und einen Adapter vonIBlogConfiguration
zuIXMLSegment
. Ich kann jetzt anrufen je nachdem, welcher Adapter für einen Gegenstand geeignet ist, ich durch das SchreibenIXMLSegment(object_to_serialize)
serialisiert werden soll.Ich konnte sogar mehr Adapter von verschiedenen anderen Dingen
IXMLSegment
aus Eiern andere alsmy.blog.xmldump
hinzufügen. ZCML hat eine Funktion, wo es eine bestimmte Richtlinie ausgeführt werden kann, wenn und nur wenn einige Ei installiert ist. Ich konnte dies nutzen habenmy.blog.rss
einen Adapter vonIRSSFeed
zuIXMLSegment
registrieren iffmy.blog.xmldump
zu installierenden geschieht, ohnemy.blog.rss
abhängig machenmy.blog.xmldump
. -
Viewlet
s sind wie kleineBrowserView
s, dass man haben kann ‚subscribe‘ an einer bestimmten Stelle innerhalb einer Seite. Ich kann nicht alle Details im Augenblick erinnern, aber diese sind sehr gut für Dinge wie Plugins, dass Sie in einer Seitenleiste angezeigt werden sollen.Ich kann mich nicht erinnern, freihändig, ob sie Teil der Basis Zope oder Plone. Ich würde empfehlen, gegen Plone verwenden, es sei denn das Problem, dass Sie tatsächlich ein echtes CMS muss versuchen zu lösen, da es ein großer und kompliziert ist Teil der Software und es neigt dazu, ein bisschen langsam.
Sie müssen nicht wirklich brauchen
Viewlet
s sowieso, daBrowserView
s sie nennen kann, entweder durch Verwendung von ‚Objekt / @@ some_browser_view‘ in einem TAL-Ausdruck oder durchqueryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
verwenden, aber sie sind ziemlich schön unabhängig. -
Marker
Interface
s. Ein Marker ist einInterface
Interface
die keine Verfahren und keine Attribute bereitstellt. Sie können einen MarkerInterface
jedes Objekt zur Laufzeit mitISomething.alsoProvidedBy
hinzufügen. So können Sie zum Beispiel Alter, welche Adapter auf ein bestimmtes Objekt gewöhnen und welcheBrowserView
s auf ihr definiert werden.
Ich entschuldige mich, dass ich nicht in genug Detail gegangen, um der Lage sein, jedem dieser Beispiele sofort zu implementieren, aber sie würden nehmen etwa ein Blog veröffentlichen jeden.
Zope-Schnittstellen können eine nützliche Art und Weise bieten zwei Teile des Codes zu entkoppeln, die nicht voneinander abhängen sollte.
sagen, wir haben eine Komponente, die wissen, wie man in Modul a.py Gruß drucken:
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
Und einige Code, dass der Bedarf einen Gruß in Modul b.py drucken:
>>> Greeter().greet()
'Hello'
Diese Anordnung macht es schwer, aus dem Code zu tauschen, dass Griffe die ohne sie zu berühren b.py Gruß (die in einem separaten Paket verteilt werden könnten). Stattdessen könnten wir ein drittes Modul c.py einzuführen, die eine IGreeter Schnittstelle definiert:
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
Jetzt können wir dies zu entkoppeln a.py verwenden und b.py. Statt eine Greeter Klasse instanziiert wird, wird b.py jetzt ein Dienstprogramm fragen die IGreeter Interface. Und a.py wird erklären, dass die Greeter-Klasse implementiert die Schnittstelle:
(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'
Ich habe noch nie Zope-Schnittstellen verwendet, aber Sie könnten erwägen, einen metaclass , die die Mitglieder der Klasse gegen die Schnittstelle bei der Initialisierung überprüft, und wenn eine Methode eine Laufzeitausnahme wirft nicht implementiert ist.
Mit Python Sie haben keine anderen Optionen. Entweder hat einen „Kompilierung“ Schritt, den Code überprüft, oder dynamisch zur Laufzeit überprüfen.