Pergunta

Eu comecei a usar interfaces Zope em meu código, e a partir de agora, elas são apenas documentação.Eu os uso para especificar quais atributos a classe deve possuir, implementá-los explicitamente nas classes apropriadas e verificá-los explicitamente onde espero que existam.Tudo bem, mas eu gostaria que eles fizessem mais, se possível, como realmente verificar se a classe implementou a interface, em vez de apenas verificar se eu disse que a classe implementa a interface.Eu li o wiki do zope algumas vezes, mas ainda não consigo ver muito mais utilidade para interfaces do que estou fazendo atualmente.Então, minha pergunta é para que mais você pode usar essas interfaces e como usá-las para mais.

Foi útil?

Solução

Você pode realmente testar se o seu objeto ou classe implementa sua interface. Para isso, você pode usar verify Módulo (você normalmente o usaria em seus testes):

>>> 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

As interfaces também podem ser usadas para definir e testar invariantes. Você pode encontrar mais informações aqui:

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

Outras dicas

Onde trabalho, usamos Interfaces para podermos usar ZCA, ou o Arquitetura de Componentes Zope, que é uma estrutura completa para criar componentes que podem ser trocados e plugados usando InterfaceS.Usamos ZCA para que possamos lidar com todos os tipos de personalizações por cliente sem necessariamente ter que bifurcar nosso software ou ter todos os muitos bits por cliente bagunçando a árvore principal.O wiki do Zope é muitas vezes bastante incompleto, infelizmente.Há uma explicação boa, mas concisa, da maioria dos recursos do ZCA em seu Página pypi da ZCA.

eu não uso Interfaces para qualquer coisa como verificar se uma classe implementa todos os métodos para um determinado Interface.Em teoria, isso pode ser útil quando você adiciona outro método a uma interface, para verificar se você se lembrou de adicionar o novo método a todas as classes que implementam a interface.Pessoalmente, prefiro fortemente criar um novo Interface sobre a modificação de um antigo.Modificando antigo Interfaces geralmente é uma péssima ideia, uma vez que estão em ovos que foram liberados para o pypi ou para o resto da sua organização.

Uma nota rápida sobre a terminologia:Aulas implemento Interfaces e objetos (instâncias de classes) fornecer InterfaceS.Se você quiser verificar se há um Interface, você escreveria ISomething.implementedBy(SomeClass) ou ISomething.providedBy(some_object).

Então, vamos a exemplos de onde o ZCA é útil.Vamos fingir que estamos escrevendo um blog, usando o ZCA para torná-lo modular.Teremos um BlogPost objeto para cada postagem, o que fornecerá um IBlogPost interface, tudo definido em nosso prático my.blog ovo.Também armazenaremos a configuração do blog em BlogConfiguration objetos que fornecem IBlogConfiguration.Usando isso como ponto de partida, podemos implementar novos recursos sem necessariamente ter que tocar my.blog de forma alguma.

A seguir está uma lista de exemplos de coisas que podemos fazer usando ZCA, sem ter que alterar a base my.blog ovo.Eu ou meus colegas de trabalho fizemos todas essas coisas (e as consideramos úteis) em projetos reais para clientes, embora não estivéssemos implementando blogs na época.:) Alguns dos casos de uso aqui poderiam ser melhor resolvidos por outros meios, como um arquivo CSS impresso.

  1. Adicionando visualizações extras (BrowserViews, geralmente registrado em ZCML com o browser:page diretiva) a todos os objetos que fornecem IBlogPost.eu poderia fazer um my.blog.printable ovo.Esse ovo registraria um BrowserView chamado print para IBlogPost, que renderiza a postagem do blog por meio de um Modelo de página Zope projetado para produzir HTML que imprima bem.Que BrowserView apareceria então no URL /path/to/blogpost/@@print.

  2. O mecanismo de assinatura de eventos no Zope.Digamos que eu queira publicar feeds RSS e gerá-los antecipadamente, e não mediante solicitação.Eu poderia criar um my.blog.rss ovo.Nesse ovo, eu registraria um assinante para eventos que fornecessem IObjectModificado (zope.lifecycleevent.interfaces.IObjectModified), em objetos que fornecem IBlogPost.Esse assinante seria chamado toda vez que um atributo fosse alterado em qualquer coisa que fornecesse IBlogPost, e eu poderia usá-lo para atualizar todos os feeds RSS nos quais a postagem do blog deveria aparecer.

    Neste caso, talvez seja melhor ter um IBlogPostModified evento que é enviado no final de cada um dos BrowserViews que modificam postagens de blog, já que IObjectModified é enviado uma vez em cada alteração de atributo - o que pode ser muito frequente por uma questão de desempenho.

  3. Adaptadores.Os adaptadores são efetivamente "lançados" de uma interface para outra.Para geeks de linguagem de programação:Adaptadores Zope implementam despacho múltiplo "aberto" em Python (por "aberto" quero dizer "você pode adicionar mais casos de qualquer ovo"), com correspondências de interface mais específicas tendo prioridade sobre correspondências menos específicas (Interface classes podem ser subclasses umas das outras, e isso faz exatamente o que você espera que faça.)

    Adaptadores de um Interface pode ser chamado com uma sintaxe muito boa, ISomething(object_to_adapt), ou pode ser consultado através da função zope.component.getAdapter.Adaptadores de vários Interfaces devem ser consultados através da função zope.component.getMultiAdapter, o que é um pouco menos bonito.

    Você pode ter mais de um adaptador para um determinado conjunto de Interfaces, diferenciado por uma string name que você fornece ao registrar o adaptador.O nome padrão é "".Por exemplo, BrowserViews são, na verdade, adaptadores que se adaptam à interface na qual estão registrados e a uma interface que a classe HTTPRequest implementa.Você também pode procurar todos dos adaptadores que são registrados a partir de uma sequência de Interfaceé para outro Interface, usando zope.component.getAdapters( (IAdaptFrom,), IAdaptTo ), que retorna uma sequência de pares (nome, adaptador).Isso pode ser usado como uma maneira muito boa de fornecer ganchos aos quais os plug-ins podem se conectar.

    Digamos que eu queira salvar todas as postagens e configurações do meu blog como um grande arquivo XML.Eu crio um my.blog.xmldump ovo que define um IXMLSegment, e registra um adaptador de IBlogPost para IXMLSegment e um adaptador de IBlogConfiguration para IXMLSegment.Agora posso chamar qualquer adaptador apropriado para algum objeto que desejo serializar escrevendo IXMLSegment(object_to_serialize).

    Eu poderia até adicionar mais adaptadores de várias outras coisas para IXMLSegment de ovos que não sejam my.blog.xmldump.ZCML possui um recurso onde pode executar uma diretiva específica se e somente se algum ovo estiver instalado.Eu poderia usar isso para ter my.blog.rss registrar um adaptador de IRSSFeed para IXMLSegment se my.blog.xmldump acontece de ser instalado, sem fazer my.blog.rss depende de my.blog.xmldump.

  4. Viewletsão como pequenos BrowserViewÉ que você pode 'inscrever-se' em um determinado local dentro de uma página.Não consigo me lembrar de todos os detalhes agora, mas eles são muito bons para coisas como plug-ins que você deseja que apareçam em uma barra lateral.

    Não me lembro de imediato se eles fazem parte da base Zope ou Plone.Eu não recomendaria usar o Plone, a menos que o problema que você está tentando resolver realmente precise de um CMS real, já que é um software grande e complicado e tende a ser um pouco lento.

    Você não precisa necessariamente Viewletde qualquer maneira, já que BrowserViews podem chamar um ao outro, usando 'object/@@some_browser_view' em uma expressão TAL ou usando queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' ), mas eles são muito legais de qualquer maneira.

  5. Marcador InterfaceS.Um marcador Interface é um Interface que não fornece métodos nem atributos.Você pode adicionar um marcador Interface qualquer objeto em tempo de execução usando ISomething.alsoProvidedBy.Isso permite, por exemplo, alterar quais adaptadores serão usados ​​em um determinado objeto e quais BrowserViews será definido nele.

Peço desculpas por não ter entrado em detalhes suficientes para poder implementar cada um desses exemplos imediatamente, mas cada um deles levaria aproximadamente uma postagem no blog.

As interfaces de zope podem fornecer uma maneira útil de dissociar duas peças de código que não devem depender uma da outra.

Digamos que temos um componente que saiba imprimir uma saudação no módulo A.Py:

>>> class Greeter(object):
...     def greet(self):
...         print 'Hello'

E algum código que precisa imprimir uma saudação no módulo B.Py:

>>> Greeter().greet()
'Hello'

Esse arranjo dificulta a troca do código que lida com a saudação sem tocar B.Py (que pode ser distribuída em um pacote separado). Em vez disso, poderíamos introduzir um terceiro módulo C.Py, que define uma interface do iGreeter:

>>> from zope.interface import Interface
>>> class IGreeter(Interface):
...     def greet():
...         """ Gives a greeting. """

Agora podemos usar isso para dissociar A.Py e B.Py. Em vez de instantar uma classe cumprimentadora, o B.Py agora solicitará um utilitário que fornece a interface do iGreeter. E A.Py declarará que a classe Greeter implementa essa 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'

Eu nunca usei interfaces de zope, mas você pode considerar escrever um metaclasse, que na inicialização verifica os membros da classe em relação à interface e aumenta uma exceção de tempo de execução se um método não for implementado.

Com Python, você não tem outras opções. Tenha uma etapa de "compilação" que inspeciona seu código ou inspecione -o dinamicamente em tempo de execução.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top