首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python中抽象类与接口的区别

Python中抽象类与接口的区别
EN

Stack Overflow用户
提问于 2008-12-16 17:32:28
回答 8查看 437.3K关注 0票数 599

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

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2008-12-16 17:59:23

您有时会看到以下内容:

代码语言:javascript
复制
class Abstract1:
    """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没有(也不需要)正式的接口契约,所以抽象和接口之间不存在Java风格的区别。如果有人努力定义一个正式的接口,它也将是一个抽象类。唯一的区别是文档字符串中声明的意图不同。

当你有鸭子类型时,抽象和接口之间的区别是令人费解的事情。

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

由于Python具有多重继承,因此您可能还会看到如下所示的内容

代码语言:javascript
复制
class SomeAbstraction:
    pass  # lots of stuff - but missing something

class Mixin1:
    def something(self):
        pass  # one implementation

class Mixin2:
    def something(self):
        pass  # another

class Concrete1(SomeAbstraction, Mixin1):
    pass

class Concrete2(SomeAbstraction, Mixin2):
    pass

这使用了一种带有混合的抽象超类来创建互不相交的具体子类。

票数 650
EN

Stack Overflow用户

发布于 2015-07-16 03:15:20

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

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

在Python中,我们可以使用抽象基类来定义和执行接口。

使用抽象基类

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

代码语言:javascript
复制
import collections
class MySet(collections.Set):
    pass

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

代码语言:javascript
复制
>>> 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中的这个实现示例

代码语言:javascript
复制
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__属性中,在定义这些函数之前阻止实例化。

代码语言:javascript
复制
import abc

例如,"effable“被定义为可以用语言表达的东西。假设我们想要定义一个抽象基类,在Python2中是可以表达的:

代码语言:javascript
复制
class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

或者在Python3中,对元类声明做了一些细微的更改:

代码语言:javascript
复制
class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

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

代码语言:javascript
复制
class MyEffable(Effable): 
    pass

并尝试实例化它:

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

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

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

代码语言:javascript
复制
class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

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

代码语言:javascript
复制
>>> me = MyEffable()
>>> print(me)
expressable!

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

结论

我们已经演示了抽象基类的创建为Python中的自定义对象定义了接口。

票数 211
EN

Stack Overflow用户

发布于 2008-12-16 17:51:35

Python >= 2.6有Abstract Base Classes

hasattr抽象基类(

Abstract Base,简称ABC)通过提供一种方法来定义接口,从而补充了鸭子类型,而其他技术如hasattr()可能会很笨拙。Python附带了许多用于数据结构(在集合模块中)、数字(在数字模块中)和流(在io模块中)的内置ABC。您可以使用ABC模块创建自己的abc。

还有Zope Interface模块,它被zope之外的项目使用,比如twisted。我对它不是很熟悉,但是有一个维基页面的here可能会有帮助。

一般来说,您不需要抽象类的概念,也不需要python中的接口(编辑过的-详细信息请参阅S.Lott的回答)。

票数 102
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/372042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档