28.8. abc —抽象 Base Class

2.6 版的新Function。

源代码: Lib/abc.py


该模块提供了在 PEP 3119中概述的用于在 Python 中定义抽象 Base Class(ABC)的基础结构;有关为何将其添加到 Python 的信息,请参阅 PEP。 (有关基于 ABC 的数字的类型层次结构,另请参见 PEP 3141numbers模块。)

collections模块具有一些从 ABC 派生的具体类;当然,这些可以进一步推导。此外,collections模块具有一些 ABC,可用于测试类或实例是否提供特定接口,例如,是否可哈希或是否为 Map。

此模块提供以下类:

  • 类别 abc. ABCMeta
    • 用于定义抽象 Base Class(ABC)的元类。

使用此元类创建一个 ABC。 ABC 可以直接子类化,然后充当混合类。您还可以将不相关的具体类(甚至是内置类)和不相关的 ABC 注册为“虚拟子类” –内置的issubclass()函数将这些及其后代视为注册 ABC 的子类,但不会注册 ABC 显示在其 MRO(方法解析 Sequences)中,也不会调用由注册 ABC 定义的方法实现(甚至不能passsuper()调用)。 [1]

使用ABCMeta元类创建的类具有以下方法:

  • register(* subclass *)
    • 将* subclass *注册为该 ABC 的“虚拟子类”。例如:
from abc import ABCMeta

class MyABC:
    __metaclass__ = ABCMeta

MyABC.register(tuple)

assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)

您还可以在抽象 Base Class 中重写此方法:

  • __subclasshook__(* subclass *)
    • (必须定义为类方法.)

检查* subclass *是否被视为此 ABC 的子类。这意味着您可以进一步自定义issubclass的行为,而无需在要考虑 ABC 的子类的每个类上调用register()。 (此类方法从 ABC 的__subclasscheck__()方法调用.)

此方法应返回TrueFalseNotImplemented。如果返回True,则* subclass 被视为此 ABC 的子类。如果它返回False,则 subclass *不会被视为此 ABC 的子类,即使它通常是一个。如果返回NotImplemented,则使用常规机制 continue 子类检查。

为了演示这些概念,请看以下示例 ABC 定义:

class Foo(object):
    def __getitem__(self, index):
        ...
    def __len__(self):
        ...
    def get_iterator(self):
        return iter(self)

class MyIterable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    def get_iterator(self):
        return self.__iter__()

    @classmethod
    def __subclasshook__(cls, C):
        if cls is MyIterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

MyIterable.register(Foo)

ABC MyIterable定义了标准的可迭代方法iter()作为抽象方法。此处给出的实现仍可以从子类中调用。 get_iterator()方法也是MyIterable抽象 Base Class 的一部分,但是在非抽象派生类中不必重写它。

此处定义的subclasshook()类方法表示,在其dict(或passmro列表访问的一个 Base Class 之一)中具有iter()方法的任何类也被视为MyIterable

最后,最后一行使Foo成为MyIterable的虚拟子类,即使它没有定义iter()方法(它使用按照len()getitem()定义的旧式可迭代协议)。请注意,这不会使get_iterator作为Foo的方法可用,因此将单独提供它。

它还提供以下装饰器:

  • abc. abstractmethod(Function)
    • 装饰器,指示抽象方法。

使用此装饰器要求该类的元类为ABCMeta或从其派生。除非实例化了所有抽象方法和属性,否则无法实例化具有从ABCMeta派生的元类的类。可以使用任何正常的“超级”调用机制来调用抽象方法。

不支持将动态方法添加到类,或在创建方法或类后try修改其抽象状态。 abstractmethod()仅影响使用常规继承派生的子类。pass ABC 的register()方法注册的“虚拟子类”不受影响。

Usage:

class C:
    __metaclass__ = ABCMeta
    @abstractmethod
    def my_abstract_method(self, ...):
        ...

Note

与 Java 抽象方法不同,这些抽象方法可能具有实现。可以pass覆盖它的类中的super()机制调用此实现。在使用协作式多重继承的框架中,这可用作超级调用的端点。

  • abc. abstractproperty([* fget * [,* fset * [,* fdel * [,* doc *]]]])
    • 内置property()的子类,指示抽象属性。

使用此函数要求该类的元类为ABCMeta或从其派生。除非实例化了所有抽象方法和属性,否则无法实例化具有从ABCMeta派生的元类的类。可以使用任何正常的“超级”调用机制来调用抽象属性。

Usage:

class C:
    __metaclass__ = ABCMeta
    @abstractproperty
    def my_abstract_property(self):
        ...

这定义了一个只读属性;您还可以使用“ long”形式的属性语句来定义读写抽象属性:

class C:
    __metaclass__ = ABCMeta
    def getx(self): ...
    def setx(self, value): ...
    x = abstractproperty(getx, setx)

Footnotes

  • [1]
    • C 程序员应注意,Python 的虚拟 Base Class 概念与 C 的概念不同。