Scopo delle interfacce Zope?
-
22-09-2019 - |
Domanda
Ho iniziato a utilizzare le interfacce di Zope nel mio codice, e fin d'ora, sono in realtà solo la documentazione. Li uso per specificare quali attributi della classe deve possedere, implementarli in modo esplicito nelle classi corrispondenti ed esplicitamente verificare la presenza di loro dove mi aspetto uno. Questo va bene, ma vorrei che facessero più, se possibile, come verificare effettivamente che la classe ha implementato l'interfaccia, invece di verificare che ho detto che la classe implementa l'interfaccia. Ho letto il wiki Zope un paio di volte, ma ancora non riesco a vedere molto di più l'uso di interfacce di quello che sto facendo attualmente. Quindi, la mia domanda è che cosa altro si può utilizzare queste interfacce per, e come si fa a usarli di più.
Soluzione
Si può effettivamente verificare se il vostro oggetto o classe implementa l'interfaccia.
Per questo si può utilizzare il modulo verify
(che si usa normalmente nelle vostre test):
>>> 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
interfacce possono essere utilizzate anche per l'impostazione e il test invarianti. E 'possibile trovare maggiori informazioni qui:
Altri suggerimenti
Dove lavoro, usiamo interfacce in modo da poter usare ZCA, o Zope Component Architecture , che è un quadro intero per realizzare componenti che sono sostituibili e Pluggable usando Interface
s. Usiamo ZCA modo da poter far fronte a tutti i tipi di personalizzazioni per-client senza necessariamente dover spendere nostro software o avere tutti i molti bit per-client rovinare l'albero principale. Il wiki Zope è spesso molto incompleta, purtroppo. C'è una spiegazione buona-but-tersa della maggior parte delle caratteristiche di ZCA sul suo pagina PyPI di ZCA .
Non faccio uso di Interface
s per una cosa del genere la verifica che una classe implementa tutti i metodi per un determinato Interface
. In teoria, questo potrebbe essere utile quando si aggiunge un altro metodo per un'interfaccia, per verificare che hai ricordato di aggiungere il nuovo metodo a tutte le classi che implementano l'interfaccia. Personalmente preferisco vivamente di creare una nuova Interface
sopra modificando una vecchia. Modifica vecchio Interfaces
è di solito una pessima idea una volta che sono in uova che sono stati rilasciati per PyPI o per il resto della vostra organizzazione.
Una breve nota sulla terminologia: classi attuare Interface
s e oggetti (istanze di classi) fornire Interface
s. Se si desidera verificare la presenza di un Interface
, si dovrebbe scrivere o ISomething.implementedBy(SomeClass)
o ISomething.providedBy(some_object)
.
Quindi, fino a esempi di dove ZCA è utile. Facciamo finta che stiamo scrivendo un blog, utilizzando lo ZCA per renderlo modulare. Avremo un oggetto BlogPost
per ogni post, che fornirà un'interfaccia IBlogPost
, tutti definiti nel nostro uovo my.blog
comodo-dandy. Ci sarà anche archivio di configurazione del blog negli oggetti BlogConfiguration
che forniscono IBlogConfiguration
. Usando questo come punto di partenza, siamo in grado di implementare nuove funzionalità senza necessariamente dover toccare my.blog
a tutti.
Quello che segue è un elenco di esempi di cose che possiamo fare utilizzando ZCA, senza dover modificare l'uovo di base my.blog
. Io oi miei collaboratori ho fatto tutte queste cose (e li ha trovati utili) su progetti reali per-client, anche se non siamo stati implementando i blog al momento. :) Alcuni dei casi d'uso qui potrebbe essere meglio risolti con altri mezzi, come ad esempio un file di stampa CSS.
-
L'aggiunta di prospettive in eccesso (
BrowserView
s, in genere registrati negli ZCML con la direttivabrowser:page
) a tutti gli oggetti che fornisconoIBlogPost
. Potrei fare un uovomy.blog.printable
. Quell'uovo registrerebbe un BrowserView chiamatoprint
perIBlogPost
, che rende il post sul blog attraverso un Zope modello di pagina progettato per produrre HTML che consente di stampare bene. QuellaBrowserView
allora apparirà in/path/to/blogpost/@@print
URL. -
Il meccanismo di sottoscrizione di eventi in Zope. Dire che voglio pubblicare feed RSS, e voglio generare in anticipo piuttosto che su richiesta. Potrei creare un uovo
my.blog.rss
. In quell'uovo, mi piacerebbe registrare un abbonato per gli eventi che forniscono IObjectModified (zope.lifecycleevent.interfaces.IObjectModified
), su oggetti che fornisconoIBlogPost
. Quella abbonato otterrebbe sarebbe chiamato ogni volta che un attributo è cambiato su qualsiasi cosa che fornisceIBlogPost
, e ho potuto usarlo per aggiornare tutti i feed RSS che il post sul blog dovrebbe apparire in.In questo caso, potrebbe essere meglio avere un evento
IBlogPostModified
che viene inviato alla fine di ciascuno deiBrowserView
s che modificano i post del blog, dal momento cheIObjectModified
ottiene sent una volta su ogni singola modifica attributo -. che potrebbe essere troppo spesso per il bene di prestazioni -
Adattatori. Gli adattatori sono effettivamente "getta" da un'interfaccia all'altra. Per i geek Linguaggio di programmazione: adattatori Zope implementare "aperto" multiple-spedizione in Python (da "aperto" Voglio dire "è possibile aggiungere più casi da ogni uovo"), con un'interfaccia più specifico partite prendendo la priorità su incontri specifici-less (
Interface
Le classi possono essere sottoclassi gli uni degli altri, e questo è esattamente quello che ci si sperare che farebbe.)Adattatori da un
Interface
possono essere chiamati con una sintassi molto bella,ISomething(object_to_adapt)
, o possono essere consultati tramite la funzionezope.component.getAdapter
. Adattatori da piùInterface
s devono essere guardato tramite la funzionezope.component.getMultiAdapter
, che è un po 'meno bella.È possibile avere più di un adattatore per un dato insieme di
Interface
s, differenziato per unname
stringa che si fornisce al momento della registrazione l'adattatore. Le impostazioni predefinite di nome a""
. Ad esempio, sono in realtàBrowserView
s adattatori che si adattano dall'interfaccia che stanno registrati su e un'interfaccia che implementa classe HTTPRequest. È anche possibile cercare tutti delle schede che vengono registrate da una sequenza diInterface
s ad un altroInterface
, utilizzandozope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
, che restituisce una sequenza di (nome, adattatore) coppie. Questo può essere usato come un bel modo per fornire i ganci per i plugin di si attaccano a.detto che volevo salvare tutti i messaggi e la configurazione del mio blog come un unico grande file XML. Creo un uovo
my.blog.xmldump
che definisce unIXMLSegment
, e registra un adattatore daIBlogPost
aIXMLSegment
e un adattatore daIBlogConfiguration
aIXMLSegment
. Ora posso chiamare a seconda di quale adattatore è adatto per un oggetto che voglio serializzare scrivendoIXMLSegment(object_to_serialize)
.Potrei anche aggiungere più schede da varie altre cose da
IXMLSegment
dalle uova diversemy.blog.xmldump
. ZCML ha una caratteristica in cui è possibile eseguire una particolare direttiva se e solo se è installato qualche uovo. Potrei usare questo per averemy.blog.rss
registrare un adattatore daIRSSFeed
aIXMLSegment
ssemy.blog.xmldump
accade per essere installato, senza faremy.blog.rss
dipenderemy.blog.xmldump
. -
Viewlet
s sono come piccoliBrowserView
s che si può avere 'sottoscrivere' ad un punto particolare all'interno di una pagina. Non riesco a ricordare tutti i dettagli in questo momento, ma questi sono molto buono per le cose come plugin che si desidera visualizzare in una barra laterale.Non riesco a ricordare due piedi se sono parte di base di Zope e Plone. Suggerirei di non utilizzare Plone a meno che il problema che si sta tentando di risolvere in realtà ha bisogno di un vero e proprio CMS, dal momento che è un pezzo di software grande e complicato e che tende ad essere un po 'lento.
Non è necessariamente effettivamente bisogno
Viewlet
s in ogni caso, dal momento cheBrowserView
s possono chiamare l'un l'altro, utilizzando 'oggetto / @@ some_browser_view' in un'espressione TAL, oppure utilizzandoqueryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
, ma sono abbastanza piacevole a prescindere. -
Interface
s Marker. UnInterface
marcatore è unInterface
che non fornisce i metodi e attributi. È possibile aggiungere un marcatoreInterface
qualsiasi oggetto in fase di esecuzione utilizzandoISomething.alsoProvidedBy
. Questo ti permette di, ad esempio, modificare quali adattatori andranno utilizzato su un particolare oggetto e cheBrowserView
s saranno definite su di esso.
Mi scuso che io non sono andato in dettaglio sufficiente per essere in grado di implementare ciascuno di questi esempi subito, ma che avrebbero preso circa un post sul blog ogni.
interfacce Zope possono fornire un modo utile per separare due parti di codice che non dovrebbe dipendere vicenda.
Supponiamo di avere un componente che sa come stampare un saluto nel modulo a.py:
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
E po 'di codice che ha bisogno di stampare un saluto nel modulo b.py:
>>> Greeter().greet()
'Hello'
Questa disposizione rende difficile scambiare il codice che gestisce il saluto senza toccare b.py (che potrebbe essere distribuito in un pacchetto separato). Invece, si potrebbe introdurre una terza c.py modulo che definisce un'interfaccia IGreeter:
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
Ora possiamo usare questo per disaccoppiare a.py e b.py. Invece di un'istanza di una classe Greeter, b.py ora chiedere un programma di utilità che fornisce l'interfaccia IGreeter. E a.py dichiarerà che la classe Greeter implementa l'interfaccia:
(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'
Non ho mai usato le interfacce Zope, ma si potrebbe non crei una metaclasse, che all'inizializzazione controlla i membri della classe contro l'interfaccia, e solleva un'eccezione di runtime se un metodo non è implementato.
Con Python non si dispone di altre opzioni. O hanno un "Compila" passo che ispeziona il codice, o dinamicamente controllarla in fase di esecuzione.