所以我在静态土地上花了大量时间后开始使用Python。我已经看到一些项目使得“接口”实际上只是没有任何实现的类。之前,我嘲笑这个想法,忽略那些项目的那一部分。但现在,我开始热衷于这个想法了。
我们很清楚,Python中的界面看起来像这样:
class ISomething(object):
def some_method():
pass
def some_other_method(some_argument):
pass
请注意,您没有将self传递给任何方法,因此要求重写该方法以进行调用。我认为这是一种很好的文档和完整性测试形式。
那么每个人对这个想法的看法是什么?我已经完成了所有C#编程的洗脑,或者这是一个好主意吗?
答案 0 :(得分:29)
我不确定这是什么意思。接口(无论如何这种形式)主要是为了解决缺少多重继承问题。但是Python有MI,所以为什么不做一个抽象类?
class Something(object):
def some_method(self):
raise NotImplementedError()
def some_other_method(self, some_argument):
raise NotImplementedError()
答案 1 :(得分:12)
在Python 2.6及更高版本中,您可以使用abstract base classes代替。这些很有用,因为您可以通过使用“isinstance”来测试某些内容是否实现了给定的ABC。像往常一样,Python中的概念并不像严格的语言那样严格执行,但它很方便。此外,还有很好的惯用方法可以使用装饰器声明抽象方法 - 请参阅上面的链接以获取示例。
答案 2 :(得分:11)
在某些情况下,接口可以非常方便。 Twisted生成fairly extensive use的Zope interfaces,而在我正在研究Zope接口的项目中效果非常好。最近打包的Enthought的特征添加了interfaces,但我对它们没有任何经验。
请注意过度使用 - 鸭子类型和协议是Python的一个基本方面,只有在绝对必要时才使用接口。
答案 3 :(得分:10)
pythonic方式是“请求宽恕而不是获得许可”。接口 all 关于接收对对象执行某些操作的权限。 Python更喜欢这个:
def quacker(duck):
try:
duck.quack():
except AttributeError:
raise ThisAintADuckException
答案 4 :(得分:6)
我认为接口不会在代码环境中添加任何内容。
Foo
并且方法为bar()
,但它不会,则会抛出AttributeError
。答案 5 :(得分:5)
看起来对我来说是不必要的 - 当我写这样的类时,我通常只使用没有方法的基类(你的ISomething
),并在实际文档中提到哪些方法子类应该覆盖
答案 6 :(得分:4)
您可以使用动态类型语言创建接口,但在编译时不会强制执行接口。如果您忘记实现(或错误!)接口的方法,静态类型语言的编译器将警告您。由于您在动态类型语言中没有收到此类帮助,因此您的接口声明仅用作文档。 (这不一定是坏事,只是你的接口声明没有提供运行时优势而不是写评论。)
答案 7 :(得分:3)
我打算用我的Python项目做类似的事情,我要添加的唯一内容是:
答案 8 :(得分:1)
我个人将接口与Zope组件架构(ZCA)结合使用。优点不是拥有接口,而是能够将它们与适配器和实用程序(单例)一起使用。
E.g。你可以创建一个适配器,它可以采用一个实现ISomething的类,但将它适应于某个接口ISomethingElse。基本上它是一个包装。
原始课程将是:
class MyClass(object):
implements(ISomething)
def do_something(self):
return "foo"
然后想象接口ISomethingElse有一个方法do_something_else()。适配器可能如下所示:
class SomethingElseAdapter(object):
implements(ISomethingElse)
adapts(ISomething)
def __init__(self, context):
self.context = context
def do_something_else():
return self.context.do_something()+"bar"
然后,您将使用组件注册表注册该适配器,然后您可以像这样使用它:
>>> obj = MyClass()
>>> print obj.do_something()
"foo"
>>> adapter = ISomethingElse(obj)
>>> print adapter.do_something_else()
"foobar"
为您提供的功能是能够使用类不直接提供的功能扩展原始类。您可以在不更改该类的情况下执行此操作(它可能位于不同的产品/库中),您只需通过不同的实现交换该适配器,而无需更改使用它的代码。这一切都是通过在初始化时注册组件来完成的。
这当然主要用于框架/库。
我认为需要一些时间来适应它,但我真的不想再没有它了。但正如之前所说的那样,你需要准确地思考它有意义的地方以及它没有的地方。当然,它本身的接口也可以作为API的文档使用。它对于单元测试也很有用,您可以测试您的类是否实际实现了该接口。最后但并非最不重要的是,我喜欢从编写界面和一些doctests开始,以了解我实际要编写的内容。
有关详细信息,您可以查看我的little introduction to it,并且有一个quite extensive description of it's API。
答案 9 :(得分:1)
Glyph Lefkowitz(Twisted fame)就在最近wrote an article on this topic。我个人认为不需要接口,而是YMMV。
答案 10 :(得分:1)
你看过PyProtocols?它有一个很好的接口实现,你应该看看。