abc ---抽象基类

源代码: Lib/abc.py


此模块提供用于定义 abstract base classes (abcs)在python中,如 PEP 3119 ;请参阅PEP了解为什么将此添加到Python中。(也见) PEP 3141 以及 numbers 关于基于abcs的数字类型层次结构的模块。)

这个 collections 模块具有一些从ABC派生的具体类;当然,这些类可以进一步派生。此外, collections.abc 子模块有一些abc,可以用来测试一个类或实例是否提供了一个特定的接口,例如,它是可散列的还是映射的。

此模块提供元类 ABCMeta 用于定义ABC和助手类 ABC 或者通过继承来定义ABC:

class abc.ABC

具有 ABCMeta 作为它的元类。使用这个类,可以通过简单地从 ABC 避免有时混淆元类用法,例如:

from abc import ABC

class MyABC(ABC):
    pass

注意 ABC 仍然是 ABCMeta 因此继承自 ABC 需要有关元类使用的常规预防措施,因为多个继承可能导致元类冲突。还可以通过传递元类关键字并使用 ABCMeta 直接,例如:

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    pass

3.4 新版功能.

class abc.ABCMeta

用于定义抽象基类(abcs)的元类。

使用此元类创建ABC。ABC可以直接子类化,然后作为类中的混合。您还可以将不相关的具体类(甚至内置类)和不相关的ABC注册为“虚拟子类”——这些子类及其后代将被内置的ABC注册子类视为 issubclass() 函数,但是注册ABC不会显示在它们的MRO(方法解析顺序)中,注册ABC定义的方法实现也不会被调用(即使通过 super()1

用的元类创建的类 ABCMeta 方法如下:

register(subclass)

寄存器 子类 作为本ABC的“虚拟子类”。例如::

from abc import ABC

class MyABC(ABC):
    pass

MyABC.register(tuple)

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

在 3.3 版更改: 返回已注册的子类,以允许用作类修饰器。

在 3.4 版更改: 检测对的调用 register() ,您可以使用 get_cache_token() 功能。

还可以在抽象基类中重写此方法:

__subclasshook__(subclass)

(必须定义为类方法。)

检查是否 子类 被认为是ABC的一个子类。这意味着您可以自定义 issubclass 更进一步,无需调用 register() 对于每一个类,您都要考虑ABC的一个子类。(此类方法是从 __subclasscheck__() ABC方法。)

此方法应返回 TrueFalseNotImplemented . 如果它回来 True , the 子类 被认为是ABC的一个子类。如果它回来 False , the 子类 不被认为是ABC的一个子类,即使它通常是ABC的一个子类。如果它回来 NotImplemented ,子类检查继续使用常规机制。

有关这些概念的演示,请看下面的示例ABC定义:

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

class MyIterable(ABC):

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

抽象基类 MyIterable 定义标准ITerable方法, __iter__() ,作为抽象方法。这里给出的实现仍然可以从子类中调用。这个 get_iterator() 方法也是 MyIterable 抽象基类,但不必在非抽象派生类中重写它。

这个 __subclasshook__() 这里定义的类方法表示任何具有 __iter__() 方法在其 __dict__ (或在它的一个基类中,通过 __mro__ 列表)被视为 MyIterable 也是。

最后,最后一行 Foo 的虚拟子类 MyIterable ,即使它没有定义 __iter__() 方法(它使用了旧式的ITerable协议,根据 __len__()__getitem__() )注意这不会使 get_iterator 可用作 Foo ,因此它是单独提供的。

这个 abc 模块还提供以下装饰:

@abc.abstractmethod

指示抽象方法的修饰符。

使用此修饰符要求类的元类是 ABCMeta 或者是从中衍生出来的。具有派生自的元类的类 ABCMeta 除非重写其所有抽象方法和属性,否则无法实例化。抽象方法可以使用任何普通的“超级”调用机制来调用。 abstractmethod() 可用于声明属性和描述符的抽象方法。

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

什么时候? abstractmethod() 与其他方法描述符结合使用时,应将其应用为最内部的装饰器,如以下用法示例所示:

class C(ABC):
    @abstractmethod
    def my_abstract_method(self, ...):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...

    @property
    @abstractmethod
    def my_abstract_property(self):
        ...
    @my_abstract_property.setter
    @abstractmethod
    def my_abstract_property(self, val):
        ...

    @abstractmethod
    def _get_x(self):
        ...
    @abstractmethod
    def _set_x(self, val):
        ...
    x = property(_get_x, _set_x)

为了正确地与抽象基类机器进行互操作,描述符必须使用 __isabstractmethod__ . 通常,此属性应为 True 如果构成描述符的任何方法是抽象的。例如,python的内置 property 等同于:

class Descriptor:
    ...
    @property
    def __isabstractmethod__(self):
        return any(getattr(f, '__isabstractmethod__', False) for
                   f in (self._fget, self._fset, self._fdel))

注解

与Java抽象方法不同,这些抽象方法可能有一个实现。可以通过调用 super() 重写它的类的机制。这对于使用合作多继承的框架中的超级调用来说是有用的。

这个 abc 模块还支持以下遗留装饰器:

@abc.abstractclassmethod

3.2 新版功能.

3.3 版后已移除: 现在可以使用 classmethod 具有 abstractmethod() 使这个装饰器成为多余的。

内置的子类 classmethod() ,指示抽象类方法。否则类似于 abstractmethod() .

此特殊情况已弃用,因为 classmethod() 当应用于抽象方法时,decorator现在正确地标识为abstract::

class C(ABC):
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...
@abc.abstractstaticmethod

3.2 新版功能.

3.3 版后已移除: 现在可以使用 staticmethod 具有 abstractmethod() 使这个装饰器成为多余的。

内置的子类 staticmethod() ,指示抽象静态方法。否则类似于 abstractmethod() .

此特殊情况已弃用,因为 staticmethod() 当应用于抽象方法时,decorator现在正确地标识为abstract::

class C(ABC):
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...
@abc.abstractproperty

3.3 版后已移除: 现在可以使用 propertyproperty.getter()property.setter()property.deleter() 具有 abstractmethod() 使这个装饰器成为多余的。

内置的子类 property() ,指示抽象属性。

此特殊情况已弃用,因为 property() 当应用于抽象方法时,decorator现在正确地标识为abstract::

class C(ABC):
    @property
    @abstractmethod
    def my_abstract_property(self):
        ...

上面的示例定义了只读属性;您还可以通过将一个或多个基础方法适当标记为抽象来定义读写抽象属性::

class C(ABC):
    @property
    def x(self):
        ...

    @x.setter
    @abstractmethod
    def x(self, val):
        ...

如果只有一些组件是抽象的,那么只有那些组件需要更新才能在子类中创建具体的属性::

class D(C):
    @C.x.setter
    def x(self, val):
        ...

这个 abc 模块还提供以下功能:

abc.get_cache_token()

返回当前抽象基类缓存令牌。

令牌是一个不透明的对象(支持相等性测试),用于标识虚拟子类的抽象基类缓存的当前版本。每次调用时令牌都会更改 ABCMeta.register() 在任何ABC上。

3.4 新版功能.

abc.update_abstractmethods(cls)

重新计算抽象类的抽象状态的函数。如果类的抽象方法在创建后已实现或更改,则应调用此函数。通常,应该从类修饰器内部调用此函数。

退货 cls ,以允许用作类装饰器。

如果 cls 不是 ABCMeta ,什么也不做。

注解

此函数假定 cls 的超类已经更新。它不更新任何子类。

3.10 新版功能.

脚注

1

C++程序员应该注意到Python的虚拟基类概念与C++的不一样。