But de Zope Interfaces?
-
22-09-2019 - |
Question
J'ai commencé à utiliser des interfaces Zope dans mon code, et que maintenant, ils sont vraiment à notre documentation. Je les utilise pour spécifier les attributs de la classe doit posséder, les mettre en œuvre explicitement dans les classes appropriées et vérifier explicitement pour eux où j'attends un. Cela est bien, mais je les aime faire plus, si possible, par exemple vérifier effectivement que la classe a mis en oeuvre l'interface, au lieu de simplement vérifier que je l'ai dit que la classe implémente l'interface. J'ai lu le wiki Zope deux ou trois fois, mais ne peut toujours pas voir l'utilisation beaucoup plus pour les interfaces que ce que je fais actuellement. Alors, ma question est que pouvez-vous utiliser ces interfaces pour les autres, et comment les utilisez-vous pour plus.
La solution
Vous pouvez réellement tester si votre objet ou la classe implémente l'interface.
Pour cela, vous pouvez utiliser le module de verify
(vous le feriez normalement utiliser 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és pour le réglage et le test invariants. Vous trouverez plus d'informations ici:
Autres conseils
Là où je travaille, nous utilisons des interfaces pour que nous puissions utiliser ZCA ou Zope Component Architecture , qui est un cadre entier pour la fabrication de composants qui sont permutables et Pluggable utilisant Interface
s. Nous utilisons ZCA pour que nous puissions faire face à toutes sortes de par client customisations sans nécessairement avoir à fourche notre logiciel ou ont tous les nombreux bits par client salissant l'arbre principal. Le wiki Zope est souvent très incomplète, malheureusement. Il y a une bonne mais laconique-explication de la plupart des fonctionnalités de ZCA sur son page pypi de ZCA .
Je n'utilise Interface
s quoi que ce soit comme vérifier qu'une classe implémente toutes les méthodes pour un Interface
donné. En théorie, cela pourrait être utile lorsque vous ajoutez une autre méthode à une interface, pour vérifier que vous avez pensé à ajouter la nouvelle méthode pour toutes les classes qui mettent en œuvre l'interface. Personnellement, je préfère fortement de créer un nouveau Interface
sur la modification d'un ancien. Modification ancienne Interfaces
est généralement une très mauvaise idée une fois qu'ils sont dans les œufs qui ont été libérés à PyPI ou au reste de votre organisation.
Une note rapide sur la terminologie: les classes outil Interface
s et objets (instances de classes) fournir Interface
s. Si vous voulez vérifier un Interface
, vous soit écrire ISomething.implementedBy(SomeClass)
ou ISomething.providedBy(some_object)
.
Alors, jusqu'à des exemples où ZCA est utile. Feignons que nous écrivons un blog, en utilisant la ZCA pour le rendre modulaire. Nous aurons un objet BlogPost
pour chaque poste, qui fournira une interface IBlogPost
, tous définis dans notre oeuf my.blog
pratique dandy. Nous allons également enregistrer la configuration du blog dans les objets BlogConfiguration
qui fournissent IBlogConfiguration
. En utilisant comme point de départ, nous pouvons mettre en œuvre de nouvelles fonctionnalités sans nécessairement avoir à toucher my.blog
du tout.
Ce qui suit est une liste d'exemples de choses que nous pouvons faire en utilisant ZCA, sans avoir à modifier l'œuf base my.blog
. I ou mes collègues ont fait toutes ces choses (et les ont trouvées utiles) sur des projets concrets pour le client, mais nous ne les blogs en œuvre à l'époque. :) Certains des cas d'utilisation ici pourraient être mieux résolus par d'autres moyens, par exemple un fichier CSS d'impression.
-
Ajout de vues supplémentaires (
BrowserView
s, généralement enregistrés dans ZCML avec la directivebrowser:page
) à tous les objets qui fournissentIBlogPost
. Je pourrais faire un oeufmy.blog.printable
. Cet œuf enregistrerait un BrowserView appeléprint
pourIBlogPost
, ce qui rend le billet de blog par un Zope page Template conçu pour produire du HTML qui imprime bien. CeBrowserView
alors apparaître à l'/path/to/blogpost/@@print
URL. -
Le mécanisme de souscription d'événement dans Zope. Disons que je veux publier flux RSS, et je veux les générer à l'avance plutôt que sur demande. Je pourrais créer un oeuf
my.blog.rss
. Dans cet œuf, j'inscrire un abonné pour les événements qui fournissent IObjectModified (zope.lifecycleevent.interfaces.IObjectModified
), sur des objets qui fournissentIBlogPost
. Ce serait abonné se faire appelé à chaque fois qu'un attribut a changé quoi que ce soit sur la fournitureIBlogPost
, et je pourrais l'utiliser pour mettre à jour tous les flux RSS que le billet de blog devrait apparaître.Dans ce cas, il pourrait être préférable d'avoir un événement
IBlogPostModified
qui est envoyé à la fin de chacun desBrowserView
s qui modifient les messages de blog, depuisIObjectModified
se sent une fois sur chaque changement d'attribut unique -. qui pourrait être trop souvent à cause de la performance - Adaptateurs
. Les adaptateurs sont effectivement « moulages » d'une interface à l'autre. Pour les geeks de langage de programmation: adaptateurs Zope mettre en œuvre « ouvert » multiples expédition en Python (par « ouvert » je veux dire «vous pouvez ajouter plus de cas de tout œuf »), avec une interface plus spécifiques de matchs en priorité sur les matchs moins spécifiques (
Interface
Les classes peuvent être sous-classes les uns des autres, et cela fait exactement ce que vous espérons qu'il le ferait.)adaptateurs d'un
Interface
peuvent être appelées avec une syntaxe très agréable,ISomething(object_to_adapt)
, ou peuvent être obtenues via la fonctionzope.component.getAdapter
. Adaptateurs de plusieursInterface
s doivent être obtenues via la fonctionzope.component.getMultiAdapter
, ce qui est un peu moins jolie.Vous pouvez avoir plus d'un adaptateur pour un ensemble donné de
Interface
s, différenciés par unname
de chaîne que vous fournissez lors de l'enregistrement de l'adaptateur. Par défaut, le nom de""
. Par exemple,BrowserView
s sont en fait des adaptateurs qui s'adaptent de l'interface qu'ils sont enregistrés sur une interface et que les outils de la classe HTTPRequête. Vous pouvez également rechercher des paires tous des adaptateurs qui sont enregistrés d'une séquence deInterface
s à un autreInterface
, en utilisantzope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
, qui retourne une séquence de (nom, adaptateur). Ceci peut être utilisé comme un moyen très agréable de fournir des crochets pour les plugins pour se joindre à.Dire que je voulais sauver tous les messages de mon blog et la configuration comme un grand fichier XML. Créer un œuf de
my.blog.xmldump
qui définit unIXMLSegment
, et enregistre un adaptateur deIBlogPost
àIXMLSegment
et un adaptateur deIBlogConfiguration
àIXMLSegment
. Je peux maintenant appeler selon adaptateur est approprié pour un objet que je veux sérialisation en écrivantIXMLSegment(object_to_serialize)
.Je pourrais même ajouter plusieurs adaptateurs de diverses autres choses à
IXMLSegment
d'oeufs autres quemy.blog.xmldump
. ZCML dispose d'une fonction où il peut exécuter une directive particulière si et seulement si un œuf est installé. Je pourrais l'utiliser pour avoirmy.blog.rss
enregistrer un adaptateur deIRSSFeed
àIXMLSegment
ssimy.blog.xmldump
arrive à installer, sans faire dépendremy.blog.rss
my.blog.xmldump
. -
Viewlet
s sont comme des petitsBrowserView
s que vous pouvez avoir « subscribe » à un endroit particulier à l'intérieur d'une page. Je ne me souviens pas de tous les détails en ce moment, mais ceux-ci sont très bonnes pour des choses comme les plugins que vous souhaitez voir apparaître dans une barre latérale.Je ne me souviens pas si désinvolture qu'ils font partie de la base Zope ou Plone. Je recommande de ne pas utiliser à moins que le problème Plone que vous essayez de résoudre réellement besoin d'un véritable CMS, car il est un grand et complexe logiciel et il a tendance à être un peu lent.
Vous n'êtes pas nécessairement réellement besoin
Viewlet
s de toute façon, puisqueBrowserView
s peuvent appeler les uns les autres, que ce soit en utilisant « objet / @@ some_browser_view » dans une expression TAL, ou en utilisantqueryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
, mais ils sont assez agréable quel que soit. -
Interface
s de marqueur. UnInterface
marqueur est unInterface
qui fournit aucune méthode et aucun attribut. Vous pouvez ajouter un marqueurInterface
tout objet à l'exécution en utilisantISomething.alsoProvidedBy
. Cela vous permet, par exemple, modifier les adaptateurs se habituera sur un objet particulier et quiBrowserView
s seront définies là-dessus.
Je suis désolé que je ne suis pas allé dans suffisamment de détails pour être en mesure de mettre en œuvre directement chacun de ces exemples là, mais ils prendraient environ un billet de blog chacun.
interfaces Zope peuvent fournir un moyen utile pour découpler deux morceaux de code qui ne devrait pas dépendre les uns des autres.
Disons que nous avons un composant qui sait comment imprimer un message d'accueil dans le module a.py:
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
Et un code qui a besoin d'imprimer un message d'accueil dans le module b.py:
>>> Greeter().greet()
'Hello'
Cet arrangement rend difficile d'échanger le code qui gère le message d'accueil sans toucher b.py (qui pourrait être distribué dans un emballage séparé). Au lieu de cela, nous pourrions introduire un troisième module c.py qui définit une interface IGreeter:
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
Maintenant, nous pouvons l'utiliser pour découpler a.py et b.py. Au lieu d'instancier une classe Greeter, b.py va maintenant demander un utilitaire fournissant l'interface IGreeter. Et a.py déclarera que la classe Greeter implémente cette interface:
(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'
Je ne l'ai jamais utilisé les interfaces Zope, mais vous pourriez envisager d'écrire un de métaclasse, qui lors de l'initialisation vérifie les membres de la classe à l'encontre de l'interface, et soulève une exception d'exécution si une méthode ne soit pas mise en oeuvre.
Avec Python vous n'avez pas d'autres options. Soit ont une étape « compilation » qui inspecte votre code, ou inspectent dynamiquement lors de l'exécution.