2009-02-16 18 views
16

因此,我在静态土地上花费大量时间后开始使用Python进行项目。我见过一些制作“接口”的项目,它们实际上只是没有任何实现的类。之前,我会嘲笑这个想法,并忽略那些项目的那一部分。但现在,我开始热衷于这个想法。Python中的“接口”:是或否?

只是让我们很清楚,在Python的接口将是这个样子:

class ISomething(object): 
    def some_method(): 
     pass 
    def some_other_method(some_argument): 
     pass 

注意,你是不通过自我的任何方法,因此要求该方法被重写,以叫做。我认为这是一种很好的文档和完整性测试形式。

那么,什么是这里的每一个人对这个想法的意见?我是否被我所做过的所有C#编程洗脑过,或者这是一个好主意?

+2

“要求将该方法重写为被调用”:但您可以调用ISomething()。some_other_method() – Miles 2009-02-16 02:32:21

+0

对我来说,这看起来不太Python。 – 2009-02-16 03:58:40

回答

10

有一些情况下,界面可以非常方便。 Twisted使fairly extensive useZope interfaces,在一个项目中,我正在研究Zope接口,工作得很好。 Enthought的特性最近增加了interfaces,但我没有任何经验。

谨防过度使用虽然 - 鸭子类型和协议的Python的一个基本方面,只有当他们是绝对必要的使用接口。

5

似乎对我来说没有必要 - 当我编写这样的类时,我通常只用基类(您的ISomething)没有方法,并在实际文档中提及子类应该覆盖的方法。

3

我即将做同样的事情与我的Python项目,唯一的事情,我想补充是:

  • 超长,深入DOC为每个接口字符串和所有的抽象方法。
  • 我会添加所有必需的参数,所以有一个确定的列表。
  • 引发异常而不是“传递”。
  • 前缀的所有方法,因此他们显然接口的一部分 - 接口美孚:DEF foo_method1()
+0

只需添加 - 特定的异常提出将NotImplementedError() – che 2009-02-16 02:36:12

6

我不认为将接口添加任何代码环境。

  • 方法定义强制执行措施的情况没有他们。如果预计的对象有像Foo和有方法bar()和简化版,它,它会抛出一个AttributeError
  • 只要确保界面方法得到定义并不能保证其正确性;无论如何,行为单元测试都需要到位。
  • 写描述你的对象需要方法必须与你在堵它作为一个接口类具有复杂的文档字符串兼容的“读这还是死亡”的页面。它只是更有效,因为你可能无论如何要去测试它。其中一个测试可以是所有兼容对象的标准,这些对象将检查每个基本方法的调用和返回类型。
10

pythonic的方式是“请求宽恕而不是获得许可”。接口是全部关于接收对对象执行某种操作的权限。 Python喜欢这样的:

def quacker(duck): 
    try: 
     duck.quack(): 
    except AttributeError: 
     raise ThisAintADuckException 
4

你可以创建一个动态类型语言的接口,但在编译时没有强制接口。如果您忘记实现(或错误输入!)接口的方法,静态类型语言的编译器会警告您。由于您在动态类型语言中没有获得任何帮助,因此您的接口声明仅用作文档。 (这不一定是坏的,只是说你的界面声明没有提供运行时优势与写评论相比)。

27

我不确定这是什么意思。无论如何,接口(这种形式的)主要是为了解决缺乏多重继承的问题。但是Python有MI,那么为什么不创建一个抽象类呢?

class Something(object): 
    def some_method(self): 
     raise NotImplementedError() 
    def some_other_method(self, some_argument): 
     raise NotImplementedError() 
11

在Python 2.6和更高版本,可以使用abstract base classes代替。这些是有用的,因为您可以通过使用“isinstance”来测试是否实现了给定的ABC。像往常一样在Python中,这个概念不像严格的语言那样严格执行,但它很方便。此外,用装饰器声明抽象方法有很好的习惯用法 - 请参阅上面的链接以获取示例。

1

我个人将接口与Zope组件体系结构(ZCA)结合使用。优点不在于具有接口,而是能够将它们与适配器和实用程序(单例)结合使用。

例如你可以创建一个适配器,它可以接受一个实现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

1

你看过吗PyProtocols?它有一个很好的接口实现,你应该看看。

相关问题