首页 文章

Python中抽象类和接口的区别

提问于
浏览
468

Python中的抽象类和接口有什么区别?

6 回答

  • 536

    您有时会看到以下内容:

    class Abstract1( object ):
        """Some description that tells you it's abstract,
        often listing the methods you're expected to supply."""
        def aMethod( self ):
            raise NotImplementedError( "Should have implemented this" )
    

    因为Python没有(并且不需要)正式的接口 Contract ,所以抽象和接口之间的Java风格区别不存在 . 如果某人经历了定义正式接口的努力,那么它也将是一个抽象类 . 唯一的区别在于docstring中声明的意图 .

    当你打鸭子时,抽象和界面之间的区别是一个分裂的东西 .

    Java使用接口,因为它没有多重继承 .

    因为Python有多重继承,所以你也可能会看到类似的东西

    class SomeAbstraction( object ):
        pass # lots of stuff - but missing something
    
    class Mixin1( object ):
        def something( self ):
            pass # one implementation
    
    class Mixin2( object ):
        def something( self ):
            pass # another
    
    class Concrete1( SomeAbstraction, Mixin1 ):
        pass
    
    class Concrete2( SomeAbstraction, Mixin2 ):
        pass
    

    这使用一种带有mixins的抽象超类来创建不相交的具体子类 .

  • 27

    Python中的抽象类和接口有什么区别?

    对象的接口是该对象上的一组方法和属性 .

    在Python中,我们可以使用抽象基类来定义和实施接口 .

    使用抽象基类

    例如,假设我们要使用 collections 模块中的一个抽象基类:

    import collections
    class MySet(collections.Set):
        pass
    

    如果我们尝试使用它,我们得到 TypeError 因为我们创建的类不支持集合的预期行为:

    >>> MySet()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Can't instantiate abstract class MySet with abstract methods
    __contains__, __iter__, __len__
    

    所以我们要求至少实现 __contains____iter____len__ . 让我们使用documentation中的这个实现示例:

    class ListBasedSet(collections.Set):
        """Alternate set implementation favoring space over speed
        and not requiring the set elements to be hashable. 
        """
        def __init__(self, iterable):
            self.elements = lst = []
            for value in iterable:
                if value not in lst:
                    lst.append(value)
        def __iter__(self):
            return iter(self.elements)
        def __contains__(self, value):
            return value in self.elements
        def __len__(self):
            return len(self.elements)
    
    s1 = ListBasedSet('abcdef')
    s2 = ListBasedSet('defghi')
    overlap = s1 & s2
    

    实现:创建抽象基类

    我们可以通过将元类设置为 abc.ABCMeta 并在相关方法上使用 abc.abstractmethod 装饰器来创建我们自己的抽象基类 . 元类将装饰函数添加到 __abstractmethods__ 属性,防止实例化,直到定义它们为止 .

    import abc
    

    例如,“effable”被定义为可以用单词表达的东西 . 假设我们想在Python 2中定义一个可行的抽象基类:

    class Effable(object):
        __metaclass__ = abc.ABCMeta
        @abc.abstractmethod
        def __str__(self):
            raise NotImplementedError('users must define __str__ to use this base class')
    

    或者在Python 3中,元类声明略有变化:

    class Effable(object, metaclass=abc.ABCMeta):
        @abc.abstractmethod
        def __str__(self):
            raise NotImplementedError('users must define __str__ to use this base class')
    

    现在,如果我们尝试在不实现接口的情况下创建一个可用的对象:

    class MyEffable(Effable): 
        pass
    

    并尝试实例化它:

    >>> MyEffable()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
    

    我们被告知我们还没有完成这项工作 .

    现在,如果我们通过提供预期的界面来遵守:

    class MyEffable(Effable): 
        def __str__(self):
            return 'expressable!'
    

    然后我们可以使用从抽象类派生的类的具体版本:

    >>> me = MyEffable()
    >>> print(me)
    expressable!
    

    我们还可以做其他事情,例如注册已经实现这些接口的虚拟子类,但我认为这超出了这个问题的范围 . 然而,此处演示的其他方法必须使用 abc 模块来调整此方法 .

    结论

    我们已经证明,Abstract Base Class的创建定义了Python中自定义对象的接口 .

  • 98

    Python> = 2.6有Abstract Base Classes .

    抽象基类(缩写为ABC)通过提供一种定义接口的方式来补充鸭子类型,当其他技术(如hasattr())会很笨拙时 . Python附带了许多用于数据结构(在集合模块中)的内置ABC,数字(在数字模块中)和流(在io模块中) . 您可以使用abc模块创建自己的ABC .

    还有Zope Interface模块,由zope之外的项目使用,如twisted . 我'm not really familiar with it, but there'是一个可能有帮助的维基页面here .

    通常,您不需要抽象类的概念,也不需要python中的接口(已编辑 - 请参阅S.Lott的答案以获取详细信息) .

  • 35

    Python实际上没有任何一个概念 .

    它使用鸭子打字,这消除了对接口的需求(至少对于计算机:-))

    Python <= 2.5:基本类显然存在,但没有明确的方法将方法标记为“纯虚拟”,因此该类不是真正抽象的 .

    Python> = 2.6:抽象基类做existhttp://docs.python.org/library/abc.html) . 并允许您指定必须在子类中实现的方法 . 我不喜欢'using'客户端使用鸭子打字 .

  • 15

    用更基本的方式来解释:界面有点像空的松饼盘 . 它是一个包含一组没有代码的方法定义的类文件 .

    抽象类是相同的,但并非所有函数都需要为空 . 有些人可以拥有代码 . 它不是严格空的 .

    为什么要区分:Python中没有太多实际差异,但在大型项目的规划级别上,谈论接口可能更常见,因为没有代码 . 特别是如果你正在使用习惯于这个术语的Java程序员 .

  • 149

    通常,接口仅在使用单继承类模型的语言中使用 . 在这些单继承语言中,如果任何类可以使用特定方法或方法集,则通常使用接口 . 同样在这些单继承语言中,抽象类用于定义类除了没有或多个方法之外的变量,或利用单继承模型来限制可以使用一组方法的类的范围 .

    支持多继承模型的语言倾向于仅使用类或抽象基类而不使用接口 . 由于Python支持多重继承,因此它不使用接口,您可能希望使用基类或抽象基类 .

    http://docs.python.org/library/abc.html

相关问题