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


当前回答

抽象类是包含一个或多个抽象方法的类。除了抽象方法,抽象类还可以有静态方法、类方法和实例方法。 但在接口的情况下,它将只有抽象的方法没有其他。因此,继承抽象类不是强制性的,但继承接口是强制性的。

其他回答

Python实际上没有这两个概念。

它使用鸭子打字,这就不需要接口了(至少对计算机来说是这样的:-))

Python <= 2.5: 基类显然是存在的,但是没有显式的方法将一个方法标记为“纯虚”,因此类并不是真正抽象的。

Python >= 2.6: 抽象基类确实存在(http://docs.python.org/library/abc.html)。并允许您指定必须在子类中实现的方法。我不太喜欢它的语法,但它的特性是存在的。大多数情况下,从“using”客户端使用duck输入可能更好。

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

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

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

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__。让我们使用文档中的实现示例:

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来创建自己的抽象基类。并使用abc。摘要方法装饰器的相关方法。元类将把修饰过的函数添加到__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模块来适应此方法。

结论

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

为了完整起见,我们应该提到PEP3119 其中引入了ABC并与接口进行了比较, 和塔林的原话。

抽象类不是完美的接口:

属于继承层次结构 是可变的

但如果你考虑用自己的方式写:

def some_function(self):
     raise NotImplementedError()

interface = type(
    'your_interface', (object,),
    {'extra_func': some_function,
     '__slots__': ['extra_func', ...]
     ...
     '__instancecheck__': your_instance_checker,
     '__subclasscheck__': your_subclass_checker
     ...
    }
)

ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...

你很快就会意识到你在白费力气 最终实现 美国广播公司(abc)。ABCMeta

美国广播公司(abc)。ABCMeta被提议作为缺少的接口功能的有用补充, 这在python这样的语言中是很合理的。

当然,在编写版本3时,它能够得到更好的增强,并添加新的语法和不可变的接口概念……

结论:

The abc.ABCMeta IS "pythonic" interface in python

有时你会看到以下情况:

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

抽象和界面之间的区别是非常细微的当你使用鸭子打字的时候。

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

因为Python具有多重继承,所以您可能还会看到类似这样的东西

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

这使用了一种带有mixin的抽象超类来创建分离的具体子类。