J'ai commencé à utiliser Zope interfaces dans mon code, et maintenant, ils sont en réalité que de la documentation. - Je les utiliser pour spécifier quels sont les attributs de la classe devrait posséder, de les implémenter explicitement dans les classes appropriées et explicitement vérifier où j'en attends. C'est très bien, mais je tiens à en faire plus si possible, comme le fait de vérifier que la classe a mis en œuvre l'interface, au lieu de simplement vérifier que j'ai dit que la classe implémente l'interface. J'ai lu le zope wiki une couple de fois, mais ne peut toujours pas voir beaucoup plus d'utilisation pour les interfaces de ce que je suis en train de faire. Donc, ma question est à quoi d'autre pouvez-vous utiliser ces interfaces, et comment les utilisez-vous pour plus.
Réponses
Trop de publicités?Là où je travaille, nous utilisons des Interfaces de sorte que nous pouvons utiliser à la ZCA, ou l' Architecture de Composants de Zope, qui est un ensemble de cadre pour la fabrication de composants sont remplaçables et enfichables à l'aide d' Interface
s. Nous utilisons la ZCA, de sorte que nous pouvons faire face à toutes sortes de client par client personnalisation, sans nécessairement avoir à fourche de notre logiciel ou avez toutes les nombreuses par client bits gâcher l'arbre principal. Le Zope wiki est souvent assez incomplet, malheureusement. Il y a un bon-mais-laconique explication de la plupart de la ZCA de fonctionnalités sur son ZCA du pypi page.
Je n'utilise pas d' Interface
s pour rien, comme vérifier qu'une classe implémente toutes les méthodes pour un Interface
. En théorie, cela peut être utile lorsque vous ajoutez une autre méthode d'une interface, pour vérifier que vous avez rappelé à ajouter la nouvelle méthode pour toutes les classes qui implémentent l'interface. Personnellement, je préfère largement à créer un nouveau Interface
sur la modification d'une ancienne. La modification de vieux - Interfaces
est généralement une très mauvaise idée une fois qu'ils sont dans les œufs qui ont été mis sur pypi ou pour le reste de votre organisation.
Une petite remarque sur la terminologie: les classes implémentent Interface
s, et les objets (instances de classes) fournissent Interface
s. Si vous voulez vérifier une Interface
, il faudrait écrire ISomething.implementedBy(SomeClass)
ou ISomething.providedBy(some_object)
.
Donc, jusqu'à des exemples de cas où la ZCA est utile. Imaginons que nous sommes en train d'écrire un blog, à l'aide de la ZCA pour le rendre modulaire. Nous allons avoir un BlogPost
objet pour chaque poste, qui sera l' IBlogPost
interface, tous définis dans notre pratique-dandy my.blog
d'œufs. Nous allons également stocker le blog de la configuration en BlogConfiguration
objets qui fournissent IBlogConfiguration
. L'utilisation de ce comme un point de départ, nous pouvons mettre en œuvre de nouvelles fonctionnalités, sans nécessairement avoir à toucher my.blog
à tous.
Ce qui suit est une liste d'exemples de choses que l'on peut faire à l'aide de la ZCA, sans avoir à modifier la base my.blog
d'œufs. Je ou mes collègues l'ont fait toutes ces choses (et il l'a trouvé utile) sur le réel pour des projets du client, si nous n'étions pas à la mise en œuvre de blogs à l'époque. :) Certains des cas d'utilisation ici pourrait être mieux résolus par d'autres moyens, tels que l'impression d'un fichier CSS.
Ajout de points de vue (
BrowserView
s, généralement enregistrés dans ZCML avec l'browser:page
"directive") à tous les objets qui fournissentIBlogPost
. Je pourrais faire unmy.blog.printable
d'œufs. Qui de l'oeuf serait inscrire un BrowserView appelésprint
pourIBlogPost
, ce qui rend le post de blog par le biais d'un Zope Page Modèle conçu pour produire le HTML qui imprime bien. Qu'BrowserView
apparaît ensuite à l'URL/path/to/blogpost/@@print
.-
L'inscription à l'événement mécanisme de Zope. Dire que je veux publier des flux RSS, et je tiens à les générer à l'avance, plutôt que sur demande. Je pourrais créer un
my.blog.rss
d'œufs. Dans l'oeuf, je voudrais enregistrer un abonnement pour des événements qui fournissent IObjectModified (zope.lifecycleevent.interfaces.IObjectModified
), sur des objets qui fournissentIBlogPost
. Que les abonnés obtenir appelée à chaque fois qu'un attribut modifié sur quoi que ce soit en fournissantIBlogPost
, et je pourrais l'utiliser pour mettre à jour tous les flux RSS que le blog devrait apparaître.Dans ce cas, il peut être préférable d'avoir un
IBlogPostModified
événement qui est envoyé à la fin de chacun desBrowserView
s que de modifier les messages de blog, depuisIObjectModified
est envoyé une fois sur chaque attribut changement qui pourrait être trop souvent pour des raisons de performances. -
Les adaptateurs. Les adaptateurs sont en fait des "jette" à partir d'une Interface à une autre. Pour la programmation, le langage des geeks: Zope adaptateurs de mettre en œuvre "ouverte" multiple à répartition en Python (par "ouvrir", je veux dire ", vous pouvez ajouter plus de cas à partir de l'œuf"), avec plus spécifiques à l'interface des matchs de prendre la priorité sur les moins-des rencontres spécifiques (
Interface
classes peuvent être des sous-classes de l'un à l'autre, et c'est exactement ce que vous espérer qu'il ferait.)Cartes à partir d'un
Interface
peut être appelée avec une très belle syntaxe,ISomething(object_to_adapt)
, ou peut être regardé par l'intermédiaire de la fonctionzope.component.getAdapter
. Les adaptateurs de plusieursInterface
s ont à être regardé par l'intermédiaire de la fonctionzope.component.getMultiAdapter
, ce qui est un peu moins jolie.Vous pouvez avoir plus d'une carte pour un ensemble donné de
Interface
s, différenciés par une chaîne de caractèresname
que vous fournissez lors de l'inscription de la carte. Le nom par défaut est""
. Par exemple,BrowserView
s sont en fait des cartes qui s'adaptent à partir de l'interface qu'ils sont enregistrés sur et une interface de l'HTTPRequest classe implémente. Vous pouvez aussi voir tous les adaptateurs qui sont enregistrés à partir d'une séquence deInterface
s à l'autreInterface
, à l'aide dezope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
, ce qui renvoie une séquence de (nom de l'adaptateur) paires. Il peut être utilisé comme une très belle façon de fournir des crochets pour les plugins de s'attacher à des.Dire que je voulais sauver tous mes articles du blog et de la configuration comme un gros fichier XML. J'ai créer un
my.blog.xmldump
d'œufs qui définit unIXMLSegment
, et les registres d'une carte d'IBlogPost
deIXMLSegment
et d'une carte d'IBlogConfiguration
deIXMLSegment
. Je peux maintenant appeler selon adaptateur est approprié pour un objet que je veux pour sérialiser en écrivantIXMLSegment(object_to_serialize)
.Je pourrais même ajouter plus de cartes à partir de divers autres choses à
IXMLSegment
d'œufs autres quemy.blog.xmldump
. ZCML a une fonction où il peut exécuter une directive particulière si et seulement si l'oeuf est installé. Je pourrais utiliser pour avoirmy.blog.rss
enregistrer une carte à partir d'IRSSFeed
deIXMLSegment
mfimy.blog.xmldump
arrive à être installé, sans faire demy.blog.rss
dépendentmy.blog.xmldump
. -
Viewlet
s sont comme des petitsBrowserView
s que vous pouvez avoir "s'abonner" à un endroit précis à l'intérieur d'une page. Je peux pas me souvenir de tous les détails maintenant, mais ce sont de très bons pour des choses comme les plugins que vous souhaitez voir apparaître dans la barre latérale.Je ne me souviens pas si désinvolte qu'ils font partie de la base de Zope ou Plone. Je déconseille l'utilisation de Plone, à moins que le problème que vous essayez de résoudre réellement besoin d'une véritable CMS, car c'est un grand et compliqué morceau de logiciel et il a tendance à être un peu lent.
Vous n'avez pas nécessairement besoin réellement
Viewlet
s de toute façon, depuisBrowserView
s pouvez appeler l'un de l'autre, soit à l'aide de l'objet/@@some_browser_view " dans un TAL expression, ou par l'utilisation d'queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
, mais ils sont assez sympa malgré tout. Marqueur
Interface
s. Un marqueurInterface
estInterface
qui ne fournit aucune méthode et sans attributs. Vous pouvez ajouter un marqueurInterface
tout objet lors de l'exécution à l'aide deISomething.alsoProvidedBy
. Ceci vous permet, par exemple, modifier des adaptateurs sera utilisée sur un objet particulier et qui,BrowserView
s sera défini sur elle.
Je m'excuse que je n'ai pas disparu dans suffisamment de détails pour être en mesure de mettre en œuvre chacun de ces exemples, tout de suite, mais qu'ils avaient de prendre environ un blog chaque.
Vous pouvez réellement tester si votre objet ou votre classe implémente votre interface. Pour cela, vous pouvez utiliser le module verify
(vous l'utiliseriez normalement dans vos tests):
>>> 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
Les interfaces peuvent également être utilisées pour définir et tester des invariants. Vous pouvez trouver plus d'informations ici:
Zope interfaces peuvent fournir un moyen utile de dissocier les deux morceaux de code qui ne devrait pas dépendre les uns des autres.
Disons que nous avons un composant qui sait comment faire pour imprimer un message d'accueil d'un module.py:
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
Et un peu de code qui a besoin d'imprimer un message d'accueil dans le module b.py:
>>> Greeter().greet()
'Hello'
Ainsi, il est difficile de remplacer le code qui gère le salut sans le toucher.b.py (qui pourrait être distribué dans un paquet séparé). Au lieu de cela, nous avons pu introduire un troisième module c.py qui définit un IGreeter interface:
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
Maintenant, nous pouvons l'utiliser pour découpler un.py et b.py. Au lieu d'instancier une classe Greeter, b.py va maintenant demander un utilitaire de fournir le IGreeter interface. Et un.py déclare que la classe Greeter implémente cette interface:
(a.py)
>>> from zope.interface import implements
>>> from zope.component import provideUtility
>>> from c import IGreeter
>>> class Greeter(object):
... implements(IGreeter)
... 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'
Je n'ai jamais utilisé d'interfaces Zope, mais vous pouvez envisager d'écrire une métaclasse qui, lors de l'initialisation, vérifie les membres de la classe par rapport à l'interface et lève une exception d'exécution si une méthode n'est pas implémentée.
Avec Python, vous n'avez pas d'autres options. Soit une étape de "compilation" qui inspecte votre code, soit une inspection dynamique au moment de l'exécution.