发布于 2010-08-26 11:59:12
简短版本
ABC在客户端和实现的类之间提供了更高级别的语义契约。
长版本
在类和它的调用者之间有一个协定。这个类承诺做某些事情,并具有某些属性。
合同有不同的层次。
在很低的级别上,协定可能包括方法的名称或其参数的数量。
在静态类型的语言中,该约定实际上是由编译器执行的。在Python语言中,您可以使用EAFP或类型自检来确认未知对象是否满足预期的约定。
但在合同中也有更高级别的语义承诺。
例如,如果有一个__str__()方法,它应该返回对象的字符串表示形式。它可以删除对象的所有内容,提交事务,并从打印机中打印出一个空白页面……但对于它应该做什么有一个共同的理解,如Python手册中所述。
这是一个特例,手册中描述了语义契约。print()方法应该做什么?它应该将对象写到打印机还是屏幕上的一行,或者其他什么?这取决于-你需要在这里阅读评论来理解完整的合同。一段简单地检查print()方法是否存在的客户端代码已经确认了约定的一部分-可以进行方法调用,但没有就调用的更高级别语义达成一致。
定义抽象基类( Abstract Base Class,ABC)是在类实现者和调用者之间产生协定的一种方式。它不仅仅是一个方法名称的列表,而是对这些方法应该做什么的共同理解。如果从这个ABC继承,您将承诺遵循注释中描述的所有规则,包括print()方法的语义。
与静态类型相比,Python的鸭子类型在灵活性方面有很多优势,但它并不能解决所有问题。ABC提供了介于Python的自由形式和静态类型语言的束缚和约束之间的中间解决方案。
发布于 2015-05-19 22:46:33
ABC的一个方便的特性是,如果你没有实现所有必要的方法(和属性),你会在实例化时得到一个错误,而不是AttributeError,很可能是很久以后,当你实际尝试使用缺失的方法时。
from abc import ABCMeta, abstractmethod
# python2
class Base(object):
__metaclass__ = ABCMeta
@abstractmethod
def foo(self):
pass
@abstractmethod
def bar(self):
pass
# python3
class Base(object, metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass
@abstractmethod
def bar(self):
pass
class Concrete(Base):
def foo(self):
pass
# We forget to declare `bar`
c = Concrete()
# TypeError: "Can't instantiate abstract class Concrete with abstract methods bar"来自https://dbader.org/blog/abstract-base-classes-in-python的示例
编辑:为了包含python3语法,感谢@PandasRocks
发布于 2010-08-26 06:58:14
它将使确定对象是否支持给定的协议变得更容易,而不必检查协议中所有方法的存在,也不会因为不支持而触发“敌人”领域的深层次异常。
https://stackoverflow.com/questions/3570796
复制相似问题