Nik*_*win 34 python zope interface zope.interface
我已经开始在我的代码中使用Zope接口,截至目前,它们实际上只是文档.我使用它们来指定类应具有的属性,在适当的类中显式实现它们,并在我期望的位置显式检查它们.这很好,但我希望他们在可能的情况下做更多的事情,比如实际验证该类是否已经实现了接口,而不仅仅是验证我已经说过该类实现了接口.我已经阅读了几次zope wiki,但仍然看不到比我目前正在做的更多的接口使用.所以,我的问题是你还可以使用这些接口,以及如何使用它们.
Ric*_*ell 52
在我工作的地方,我们使用接口,以便我们可以使用ZCA或Zope组件架构,这是一个整体框架,用于制作可交换和使用Interface
s 可插拔的组件.我们使用ZCA,以便我们可以处理所有类型的每个客户端自定义,而无需分叉我们的软件或让所有许多每个客户端的内容弄乱主树.不幸的是,Zope wiki通常很不完整.在ZCA的pypi页面上,大部分ZCA的功能都有一个很好但很简洁的解释.
我没有使用Interface
s来检查类是否实现了给定的所有方法Interface
.理论上,当您向接口添加另一个方法时,这可能很有用,以检查您是否记得将新方法添加到实现该接口的所有类中.我个人更喜欢创建一个新Interface
的修改旧的.Interfaces
一旦他们被释放到pypi或你的组织的其他人的鸡蛋中,修改旧的通常是一个非常糟糕的主意.
关于术语的快速说明:类实现 Interface
s,对象(类的实例)提供 Interface
s.如果你想检查一个Interface
,你会写ISomething.implementedBy(SomeClass)
或ISomething.providedBy(some_object)
.
所以,直到ZCA有用的例子.让我们假装我们正在编写一个博客,使用ZCA使其模块化.我们将为BlogPost
每个帖子提供一个对象,它将提供一个IBlogPost
界面,所有这些都在我们方便的花花公子my.blog
鸡蛋中定义.我们还将博客的配置存储在BlogConfiguration
提供的对象中IBlogConfiguration
.以此为出发点,我们可以实现新功能而无需触摸my.blog
.
以下列出了我们可以通过使用ZCA完成的事情示例,而无需更改基础my.blog
蛋.我或我的同事已经在真正的for-client项目中完成了所有这些事情(并且发现它们很有用),尽管我们当时没有实现博客.:)这里的一些用例可以通过其他方法更好地解决,例如打印CSS文件.
将额外的视图(BrowserView
通常在带有指令的ZCML中注册browser:page
)添加到提供的所有对象IBlogPost
.我可以做一个my.blog.printable
鸡蛋.这鸡蛋会注册一个名为BrowserView中print
的IBlogPost
,这使得通过博客文章Zope页面模板设计生成HTML,打印好听.那BrowserView
将出现在URL上/path/to/blogpost/@@print
.
Zope中的事件订阅机制.假设我想发布RSS提要,我想提前生成它们而不是根据请求生成它们.我可以创造一个my.blog.rss
鸡蛋.在那个鸡蛋中,我会为提供IObjectModified(zope.lifecycleevent.interfaces.IObjectModified
)的事件注册订阅者 IBlogPost
.每当某个属性在提供的任何内容上发生更改时,该订阅者就会被调用IBlogPost
,我可以使用它来更新博客帖子应该出现的所有RSS提要.
在这种情况下,最好IBlogPostModified
在每个BrowserView
修改博客帖子的结尾处发送一个事件,因为IObjectModified
每次单个属性更改都会发送一次 - 这可能是为了性能而经常发生的.
适配器.适配器实际上是从一个接口"转换"到另一个接口.对于编程语言极客:Zope适配器在Python中实现"开放"多分派(通过"开放"我的意思是"你可以从任何蛋中添加更多案例"),更具体的接口匹配优先于特定于较少的匹配(Interface
类可以是彼此的子类,这正是你希望它会做的.)
Interface
可以使用非常好的语法调用一个适配器ISomething(object_to_adapt)
,或者可以通过该函数查找zope.component.getAdapter
.Interface
必须通过该函数查找来自多个s的适配器zope.component.getMultiAdapter
,这稍微不那么漂亮.
对于给定的Interface
s 集合,您可以有多个适配器,区别name
在于您在注册适配器时提供的字符串.名称默认为""
.例如,BrowserView
s实际上是适配器,它们可以从它们注册的接口和HTTPRequest类实现的接口进行调整.您还可以查看所有已注册的从一个序列的适配器Interface
s到另一个Interface
,使用zope.component.getAdapters( (IAdaptFrom,), IAdaptTo )
,它返回的(姓名,适配器)对的序列.这可以作为一种非常好的方式来为插件提供挂钩以附加自己.
假设我想将我所有博客的帖子和配置保存为一个大的XML文件.我创建一个my.blog.xmldump
蛋其限定IXMLSegment
,并注册从适配器IBlogPost
到IXMLSegment
和从适配器IBlogConfiguration
到IXMLSegment
.我现在可以调用哪个适配器适合我想要通过编写序列化的某个对象IXMLSegment(object_to_serialize)
.
我甚至可以IXMLSegment
从其他各种东西中添加更多的适配器my.blog.xmldump
.当且仅当安装了一些鸡蛋时,ZCML才能运行特定的指令.我可以使用它来有my.blog.rss
登记从适配器IRSSFeed
到IXMLSegment
IFF my.blog.xmldump
恰好可以安装,而不会使my.blog.rss
依赖my.blog.xmldump
.
Viewlet
s就像小BrowserView
s,你可以"订阅"页面内的特定位置.我现在不记得所有的细节,但是这些对于想要出现在侧边栏中的插件非常有用.
我不记得他们是否是基础Zope或Plone的一部分.我建议不要使用Plone,除非你试图解决的问题实际上需要一个真正的CMS,因为它是一个庞大而复杂的软件,它往往有点慢.
你不一定真的需要Viewlet
s,因为BrowserView
s可以通过在TAL表达式中使用'object/@@ some_browser_view'或者使用来调用彼此queryMultiAdapter( (ISomething, IHttpRequest), name='some_browser_view' )
,但是无论如何它们都非常好.
马克Interface
.标记Interface
是不Interface
提供方法而不提供属性的标记.您可以Interface
在运行时使用添加标记任何对象ISomething.alsoProvidedBy
.例如,这允许您更改将在特定对象上使用哪些适配器以及BrowserView
将在其上定义哪些适配器.
我很抱歉,我没有详细说明能够立即实施这些例子,但他们每个人都会大约发一篇博文.
Rus*_*vak 23
您实际上可以测试您的对象或类是否实现了您的接口.为此您可以使用verify
模块(通常在测试中使用它):
>>> 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
Run Code Online (Sandbox Code Playgroud)
接口也可用于设置和测试不变量.您可以在这里找到更多信息:
http://www.muthukadan.net/docs/zca.html#interfaces
Dav*_*ick 19
Zope接口可以提供一种有用的方法来解耦两个不应相互依赖的代码.
假设我们有一个知道如何在模块a.py中打印问候语的组件:
>>> class Greeter(object):
... def greet(self):
... print 'Hello'
Run Code Online (Sandbox Code Playgroud)
还有一些需要在模块b.py中打印问候语的代码:
>>> Greeter().greet()
'Hello'
Run Code Online (Sandbox Code Playgroud)
这种安排使得很难交换处理问候语的代码,而不会触及b.py(可能分布在单独的包中).相反,我们可以引入第三个模块c.py来定义IGreeter接口:
>>> from zope.interface import Interface
>>> class IGreeter(Interface):
... def greet():
... """ Gives a greeting. """
Run Code Online (Sandbox Code Playgroud)
现在我们可以用它来解耦a.py和b.py. 而不是实例化Greeter类,b.py现在将要求提供IGreeter接口的实用程序.并且a.py将声明Greeter类实现该接口:
(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'
Run Code Online (Sandbox Code Playgroud)