28.8. abc — 抽象基类

2.6 版新增。

源代码: Lib/abc.py


本模块提供基础设施为定义 抽象基类 (ABC) 在 Python 中,如提纲于 PEP 3119 ;见 PEP 了解为什么要把这添加到 Python (另请参阅 PEP 3141 numbers 模块关于基于 ABC 的数字类型层次结构)。

The collections module has some concrete classes that derive from ABCs; these can, of course, be further derived. In addition the collections module has some ABCs that can be used to test whether a class or instance provides a particular interface, for example, is it hashable or a mapping.

This module provides the following class:

class abc. ABCMeta

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

使用此元类能创建 ABC (抽象基类)。可以直接子类化 ABC,然后充当混合类。还可以把不相关具体类 (甚至是内置类) 和不相关 ABC 注册成 "虚拟子类" – 将把这些类及它们的后代认为是注册 ABC 的子类通过内置 issubclass() 函数,但注册的 ABC 既不会出现在它们的 MRO (方法分辨次序) 中,由注册的 ABC 定义的方法实现也不可调用 (甚至无法透过 super() ). [1]

类创建采用元类化的 ABCMeta 拥有以下方法:

register ( subclass )

注册 subclass 作为此 ABC 的 "虚拟子类"。例如:

from abc import ABCMeta
class MyABC:
    __metaclass__ = ABCMeta
MyABC.register(tuple)
assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)
						

也可以覆盖抽象基类中的此方法:

__subclasshook__ ( subclass )

(必须定义成类方法)。

校验是否 subclass 被认为是此 ABC 的子类。这意味着可以定制行为若 issubclass 进一步不需要调用 register() 对于想要考虑子类化 ABC 的各类 (调用此类方法是从 __subclasscheck__() 方法对于 ABC)。

此方法应返回 True , False or NotImplemented 。若它返回 True subclass 被认为是此 ABC 的子类。若它返回 False subclass 不被认为是此 ABC 的子类,即使它通常是。若它返回 NotImplemented ,采用通常机制继续校验子类。

为演示这些概念,查看这些范例 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 抽象基类,但不必在非抽象派生类覆写它。

The __subclasshook__() 类方法定义在这里说任何类拥有 __iter__() 方法在其 __dict__ (或在其基类,访问凭借 __mro__ 列表) 被认为是 MyIterable 也。

最终,最后行制作 Foo 虚拟子类化的 MyIterable ,即使它没有定义 __iter__() 方法 (使用旧式可迭代协议,其定义在术语 __len__() and __getitem__() )。注意,这不会使 get_iterator 可用作方法对于 Foo ,所以它是单独提供的。

It also provides the following decorators:

abc. abstractmethod ( function )

指示抽象方法的装饰器。

使用此装饰器要求类的元类是 ABCMeta 或是来自它的派生。拥有元类的类派生自 ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. The abstract methods can be called using any of the normal ‘super’ call mechanisms.

Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are not supported. The abstractmethod() only affects subclasses derived using regular inheritance; “virtual subclasses” registered with the ABC’s register() method are not affected.

用法:

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

注意

Unlike Java abstract methods, these abstract methods may have an implementation. This implementation can be called via the super() mechanism from the class that overrides it. This could be useful as an end-point for a super-call in a framework that uses cooperative multiple-inheritance.

abc. abstractproperty ( [ fget [ , fset [ , fdel [ , doc ] ] ] ] )

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

Using this function requires that the class’s metaclass is ABCMeta 或是来自它的派生。拥有元类的类派生自 ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. The abstract properties can be called using any of the normal ‘super’ call mechanisms.

用法:

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

This defines a read-only property; you can also define a read-write abstract property using the ‘long’ form of property declaration:

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

脚注

[1] C++ programmers should note that Python’s virtual base class concept is not the same as C++’s.

上一话题

28.7. contextlib — 实用程序为 with 语句上下文

下一话题

28.9. atexit — 退出处理程序

本页