Python中抽象类和接口之间的区别

问题:Python中抽象类和接口之间的区别

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

What is the difference between abstract class and interface in Python?


回答 0

有时您会看到以下内容:

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

当您进行鸭类打字时,抽象和接口之间的区别是令人不解的事情。

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

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

What you’ll see sometimes is the following:

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" )

Because Python doesn’t have (and doesn’t need) a formal Interface contract, the Java-style distinction between abstraction and interface doesn’t exist. If someone goes through the effort to define a formal interface, it will also be an abstract class. The only differences would be in the stated intent in the docstring.

And the difference between abstract and interface is a hairsplitting thing when you have duck typing.

Java uses interfaces because it doesn’t have multiple inheritance.

Because Python has multiple inheritance, you may also see something like this

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

This uses a kind of abstract superclass with mixins to create concrete subclasses that are disjoint.


回答 1

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.ABCMetaabc.abstractmethod在相关方法上使用装饰器来创建自己的抽象基类。元类将被装饰的函数添加到__abstractmethods__属性中,从而防止实例化直到定义它们。

import abc

例如,“有效的”被定义为可以用词表达的东西。假设我们想在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中的自定义对象定义了接口。

What is the difference between abstract class and interface in Python?

An interface, for an object, is a set of methods and attributes on that object.

In Python, we can use an abstract base class to define and enforce an interface.

Using an Abstract Base Class

For example, say we want to use one of the abstract base classes from the collections module:

import collections
class MySet(collections.Set):
    pass

If we try to use it, we get an TypeError because the class we created does not support the expected behavior of sets:

>>> 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__

So we are required to implement at least __contains__, __iter__, and __len__. Let’s use this implementation example from the 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

Implementation: Creating an Abstract Base Class

We can create our own Abstract Base Class by setting the metaclass to abc.ABCMeta and using the abc.abstractmethod decorator on relevant methods. The metaclass will be add the decorated functions to the __abstractmethods__ attribute, preventing instantiation until those are defined.

import abc

For example, “effable” is defined as something that can be expressed in words. Say we wanted to define an abstract base class that is effable, in Python 2:

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

Or in Python 3, with the slight change in metaclass declaration:

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

Now if we try to create an effable object without implementing the interface:

class MyEffable(Effable): 
    pass

and attempt to instantiate it:

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

We are told that we haven’t finished the job.

Now if we comply by providing the expected interface:

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

we are then able to use the concrete version of the class derived from the abstract one:

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

There are other things we could do with this, like register virtual subclasses that already implement these interfaces, but I think that is beyond the scope of this question. The other methods demonstrated here would have to adapt this method using the abc module to do so, however.

Conclusion

We have demonstrated that the creation of an Abstract Base Class defines interfaces for custom objects in Python.


回答 2

Python> = 2.6具有抽象基类

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

还有一个Zope接口模块,该模块由zope外部的项目使用,例如扭曲。我不是很熟悉,但有一个wiki页面在这里可能会有帮助。

通常,您不需要抽象类或python中的接口的概念(已编辑-有关详细信息,请参见S.Lott的答案)。

Python >= 2.6 has Abstract Base Classes.

Abstract Base Classes (abbreviated ABCs) complement duck-typing by providing a way to define interfaces when other techniques like hasattr() would be clumsy. Python comes with many builtin ABCs for data structures (in the collections module), numbers (in the numbers module), and streams (in the io module). You can create your own ABC with the abc module.

There is also the Zope Interface module, which is used by projects outside of zope, like twisted. I’m not really familiar with it, but there’s a wiki page here that might help.

In general, you don’t need the concept of abstract classes, or interfaces in python (edited – see S.Lott’s answer for details).


回答 3

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

它使用鸭子类型,从而消除了对接口的需求(至少对于计算机:-)。

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

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

Python doesn’t really have either concept.

It uses duck typing, which removed the need for interfaces (at least for the computer :-))

Python <= 2.5: Base classes obviously exist, but there is no explicit way to mark a method as ‘pure virtual’, so the class isn’t really abstract.

Python >= 2.6: Abstract base classes do exist (http://docs.python.org/library/abc.html). And allow you to specify methods that must be implemented in subclasses. I don’t much like the syntax, but the feature is there. Most of the time it’s probably better to use duck typing from the ‘using’ client side.


回答 4

用更基本的方式解释:接口有点像一个空的松饼锅。这是一个类文件,带有一组没有代码的方法定义。

抽象类是一回事,但并非所有功能都必须为空。有些可以有代码。并非严格意义上是空的。

为什么要区分:Python并没有太大的实际区别,但是在大型项目的计划级别上,谈论接口可能更常见,因为没有代码。尤其是在您与习惯该术语的Java程序员一起工作时。

In a more basic way to explain: An interface is sort of like an empty muffin pan. It’s a class file with a set of method definitions that have no code.

An abstract class is the same thing, but not all functions need to be empty. Some can have code. It’s not strictly empty.

Why differentiate: There’s not much practical difference in Python, but on the planning level for a large project, it could be more common to talk about interfaces, since there’s no code. Especially if you’re working with Java programmers who are accustomed to the term.


回答 5

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

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

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

In general, interfaces are used only in languages that use the single-inheritance class model. In these single-inheritance languages, interfaces are typically used if any class could use a particular method or set of methods. Also in these single-inheritance languages, abstract classes are used to either have defined class variables in addition to none or more methods, or to exploit the single-inheritance model to limit the range of classes that could use a set of methods.

Languages that support the multiple-inheritance model tend to use only classes or abstract base classes and not interfaces. Since Python supports multiple inheritance, it does not use interfaces and you would want to use base classes or abstract base classes.

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


回答 6

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

Abstract classes are classes that contain one or more abstract methods. Along with abstract methods, Abstract classes can have static, class and instance methods. But in case of interface, it will only have abstract methods not other. Hence it is not compulsory to inherit abstract class but it is compulsory to inherit interface.


回答 7

为了完整起见,我们应该提到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

For completeness, we should mention PEP3119 where ABC was introduced and compared with interfaces, and original Talin’s comment.

The abstract class is not perfect interface:

  • belongs to the inheritance hierarchy
  • is mutable

But if you consider writing it your own way:

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
...

you’ll quite fast realize that you’re inventing the wheel to eventually achieve abc.ABCMeta

abc.ABCMeta was proposed as a useful addition of the missing interface functionality, and that’s fair enough in a language like python.

Certainly, it was able to be enhanced better whilst writing version 3, and adding new syntax and immutable interface concept …

Conclusion:

The abc.ABCMeta IS "pythonic" interface in python