通过zope.interface解决的抽象基类,接口的继承有哪些限制?
在Jeff在2010年给出的关于接口的后续谈话中,在11:50,Jeff认为使用由您提供的,是没有继承层次结构的。为什么这很重要?
如果我想使用一个接口并从另一个基类继承行为,Python会给我多个继承的机会。我知道应该避免多重继承,而组合设计被认为是另一种选择,但在这种情况下,我并不是从abc继承行为,而是一个接口,所以在行为意义上,我并不是真正的多重继承。
我不明白继承的论点..。
提前感谢你分享你的见解。
编辑,更新视频链接:通过回车机。
发布于 2016-12-14 07:41:19
这段视频在2016年12月似乎还没有发布,但我同意你的观点,即接口继承没有实现继承那么麻烦。例如,请参见https://softwareengineering.stackexchange.com/a/260354。
然而,zope.interface“提供者”关系将我们从继承层次结构中解放出来的一种感觉是,它允许对象提供接口,即使它们的类没有提供接口。https://docs.zope.org/zope.interface/README.html#declaring-provided-interfaces展示了直接提供接口的对象的示例,尽管它们各自的类没有提供接口。
例如,如果IWriter接口需要write和flush方法,那么定义顶级write和flush函数(并调用zope.interface.moduleProvides(IWriter))的模块提供了该接口,尽管模块一般不需要。
这也是Zope接口方法不将self命名为参数的原因-- self是类实例方法特有的实现细节。
对于包装另一个对象并动态映射其方法的对象,单个对象提供接口的能力变得特别有用。
例如,假设我们有:
class IWriter(zope.interface.Interface):
def write(s):
"""Write stuff"""
def flush():
"""Flush stuff"""
class TextWriter:
zope.interface.implements(IWriter)
def write(self, s):
...
def flush(self):
...
tw = TextWriter()
do_something(tw)如果我们看到tw输出有时不被刷新的问题,我们可以使用TextWriter方法来显示调试信息(例如log(timestamp, caller, methodname))。但是,生成timestamp和caller信息的代码很复杂,需要在多个地方添加。现在,每个TextWriter实例都将显示调试信息。
相反,我们可以将感兴趣的特定TextWriter封装在一个记录其方法调用的包装器对象中。
class DebugWrapper:
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, name):
... # generate timestamp and caller
log(timestamp, caller, name)
return getattr(self._wrapped, name)
dtw = DebugWrapper(tw)
do_something(dtw)注意,DebugWrapper是泛型的。它可以包裹任何物体。它可以从一个单独的库导入。它独立于IWriter接口,这很好,因为我们可以更容易地在其他地方重用它。
但是,如果do_something函数希望接收接口IWriter的提供程序,那么我们现在遇到的问题是,dtw满足接口语法,但没有“正式”提供接口。
这是一个重要的区别。
接口不只是定义语法签名。它们还定义了语法的语义意义。通过接口,我们可以指定提供相同方法的两个对象是否实际上提供相同的语义。这与Python常用的鸭子类型有很大的不同,因为相同的语法意味着相同的语义。
无论如何,我们问题的解决方案是通知每个人,dtw对象确实提供了IWriter接口,尽管它的类DebugWrapper没有提供。
zope.interface.directlyProvides(dtw, IWriter)https://softwareengineering.stackexchange.com/questions/245068
复制相似问题