Python中的抽象类和接口有什么区别?
#1楼
用更基本的方式来解释:界面有点像空的松饼盘。 它是一个包含一组没有代码的方法定义的类文件。
抽象类是相同的,但并非所有函数都需要为空。 有些人可以有代码。 它不是严格空的。
为什么要区分:Python中没有太多实际差异,但在大型项目的规划级别上,谈论接口可能更常见,因为没有代码。 特别是如果您正在使用习惯于该术语的Java程序员。
#2楼
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__
, __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.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中自定义对象的接口。
#3楼
Python实际上没有任何一个概念。
它使用duck typing,这消除了对接口的需求(至少对于计算机:-))
Python <= 2.5:基本类显然存在,但没有明确的方法将方法标记为“纯虚拟”,因此该类不是真正抽象的。
Python> = 2.6:确实存在抽象基类( http://docs.python.org/library/abc.html )。 并允许您指定必须在子类中实现的方法。 我不太喜欢语法,但功能就在那里。 大多数情况下,从'using'客户端使用duck typing可能更好。
#4楼
Python> = 2.6具有抽象基类 。
抽象基类(缩写为ABC)通过提供一种定义接口的方法来补充鸭子类型,当其他技术如hasattr()将是笨拙的。 Python附带了许多用于数据结构(在集合模块中)的内置ABC,数字(在数字模块中)和流(在io模块中)。 您可以使用abc模块创建自己的ABC。
还有Zope接口模块,由zope之外的项目使用,如twisted。 我不是很熟悉,但有一个wiki页面在这里可能会有帮助。
通常,您不需要抽象类的概念或python中的接口(已编辑 - 请参阅S.Lott的答案以获取详细信息)。
#5楼
您有时会看到以下内容:
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没有(并且不需要)正式的接口契约,所以抽象和接口之间的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的抽象超类来创建不相交的具体子类。
#6楼
通常,接口仅在使用单继承类模型的语言中使用。 在这些单继承语言中,如果任何类可以使用特定方法或一组方法,则通常使用接口。 同样在这些单继承语言中,除了没有或多个方法之外,抽象类还用于定义类变量,或者利用单继承模型来限制可以使用一组方法的类的范围。
支持多继承模型的语言倾向于仅使用类或抽象基类而不使用接口。 由于Python支持多重继承,因此它不使用接口,您可能希望使用基类或抽象基类。
http://docs.python.org/library/abc.html
#7楼
抽象类是包含一个或多个抽象方法的类。 与抽象方法一起,抽象类可以具有静态,类和实例方法。 但是在接口的情况下,它只有抽象方法而不是其他方法。 因此,继承抽象类不是强制性的,但继承接口是强制性的。