Python Zope接口的用途?

Python Zope接口的用途?,python,interface,zope,zope.interface,Python,Interface,Zope,Zope.interface,我已经开始在代码中使用Zope接口,到目前为止,它们实际上只是文档。我使用它们来指定类应该拥有哪些属性,在适当的类中显式实现它们,并在我期望的地方显式检查它们。这很好,但是如果可能的话,我希望他们做更多的工作,比如实际验证类是否实现了接口,而不仅仅是验证我说过的类是否实现了接口。我已经阅读了ZopeWiki好几次了,但是仍然看不到界面比我现在所做的更多的用途。所以,我的问题是,您还可以使用这些接口,以及如何使用这些接口。< p>我从未使用过Zope接口,但是您可能会考虑编写一个,它在初始化时检查

我已经开始在代码中使用Zope接口,到目前为止,它们实际上只是文档。我使用它们来指定类应该拥有哪些属性,在适当的类中显式实现它们,并在我期望的地方显式检查它们。这很好,但是如果可能的话,我希望他们做更多的工作,比如实际验证类是否实现了接口,而不仅仅是验证我说过的类是否实现了接口。我已经阅读了ZopeWiki好几次了,但是仍然看不到界面比我现在所做的更多的用途。所以,我的问题是,您还可以使用这些接口,以及如何使用这些接口。

< p>我从未使用过Zope接口,但是您可能会考虑编写一个,它在初始化时检查对接口的类成员,如果没有实现一个方法,则会引发运行时异常。


使用Python,您没有其他选择。可以使用“编译”步骤检查代码,也可以在运行时动态检查代码。

您可以实际测试对象或类是否实现了接口。 为此,您可以使用
verify
模块(您通常会在测试中使用它):

接口还可用于设置和测试不变量。 您可以在此处找到更多信息:


Zope接口可以提供一种有用的方法来解耦不应该相互依赖的两段代码

假设我们有一个组件知道如何在模块a.py中打印问候语:

>>> class Greeter(object):
...     def greet(self):
...         print 'Hello'
以及一些需要在模块b.py中打印问候语的代码:

>>> Greeter().greet()
'Hello'
这种安排使得在不接触b.py(可能在单独的包中分发)的情况下很难交换处理问候语的代码。相反,我们可以引入第三个模块c.py,它定义了一个IGreeter接口:

>>> from zope.interface import Interface
>>> class IGreeter(Interface):
...     def greet():
...         """ Gives a greeting. """
(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'
现在我们可以用它来解耦a.py和b.py。b.py不再实例化Greeter类,而是请求提供IGreeter接口的实用程序。并且a.py将声明Greeter类实现该接口:

>>> from zope.interface import Interface
>>> class IGreeter(Interface):
...     def greet():
...         """ Gives a greeting. """
(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'

在我工作的地方,我们使用接口,这样我们就可以使用ZCA或,这是一个使用
Interface
s制作可交换和可插拔组件的整体框架。我们使用ZCA,这样我们就可以处理各种各样的每客户端定制,而不必使用我们的软件,也不必让所有的每客户端位弄乱主树。不幸的是,Zope wiki通常是不完整的。有一个很好的,但简洁的解释,大部分的ZCA的特点,在其上

我不使用
Interface
s来检查类是否实现了给定
接口的所有方法。理论上,当您向接口添加另一个方法时,这可能会很有用,以检查您是否记得将新方法添加到实现该接口的所有类中。就我个人而言,我更喜欢创建一个新的
接口
,而不是修改一个旧接口。修改旧的
接口
通常是一个非常糟糕的主意,因为它们已经发布到pypi或您的组织的其他部分

关于术语的简要说明:类实现
接口
s,对象(类的实例)提供
接口
s。如果要检查
接口
,可以编写
ISomething.implementedBy(SomeClass)
ISomething.providedBy(someu对象)

因此,下面是ZCA有用的例子。让我们假设我们正在写一个博客,使用ZCA将其模块化。我们将为每篇文章提供一个
BlogPost
对象,它将提供一个
IBlogPost
接口,所有这些都是在我们方便的dandy
my.blog
egg中定义的。我们还将博客的配置存储在
BlogConfiguration
对象中,这些对象提供
IBlogConfiguration
。以此为出发点,我们可以实现新的功能,而无需触及
my.blog

下面是使用ZCA可以做的事情的示例列表,无需更改基本
my.blog
egg。我或我的同事已经在real for client项目上完成了所有这些工作(并发现它们很有用),尽管当时我们没有实现博客:这里的一些用例可以通过其他方式更好地解决,比如打印CSS文件

  • 向提供
    IBlogPost
    的所有对象添加额外视图(
    BrowserView
    s,通常使用
    browser:page
    指令注册)。我可以制作一个
    my.blog.printable
    egg。该egg将为
    IBlogPost
    注册一个名为
    print
    的浏览视图,该视图通过一个设计用于生成打印效果良好的HTML的浏览器来呈现博客文章。然后,
    BrowserView
    将出现在URL
    /path/to/blogpost/@@print

  • Zope中的事件订阅机制。假设我想发布RSS提要,我想提前生成它们,而不是根据请求生成。我可以创建一个
    my.blog.rss
    egg。在该egg中,我将为提供
    IBlogPost
    的对象上提供(
    zope.lifecycleevent.interfaces.IObjectModified
    )的事件注册订阅服务器。每当提供
    IBlogPost
    的任何内容的属性发生更改时,该订阅者都会被调用,我可以使用它来更新博客文章应该出现在其中的所有RSS提要

    在这种情况下,最好在每个修改博客文章的
    BrowserView
    末尾发送一个
    IBlogPostModified
    事件,因为
    IObjectModified
    在每个属性更改时都会发送一次,这对于性能来说可能太频繁了

  • 适配器。适配器实际上是从一个接口到另一个接口的“强制转换”。适用于编程语言极客:Zope adapte