28.8. abc — 抽象基类 — Python 文档
28.8. 美国广播公司 — 抽象基类
2.6 版中的新功能。
源代码: :source:`Lib/abc.py`
该模块提供了在 Python 中定义 抽象基类 (ABC) 的基础结构,如 PEP 3119 中所述; 请参阅 PEP 了解为什么将其添加到 Python 中。 (另请参阅 PEP 3141 和 numbers 模块,了解基于 ABC 的数字的类型层次结构。)
collections 模块有一些从 ABC 派生的具体类; 当然,这些还可以进一步推导出来。 此外,collections 模块有一些 ABC,可用于测试类或实例是否提供特定接口,例如,它是否是可散列的或是否是映射。
该模块提供以下类:
- class abc.ABCMeta
用于定义抽象基类 (ABC) 的元类。
使用这个元类来创建一个 ABC。 ABC 可以直接子类化,然后充当混合类。 您还可以将不相关的具体类(甚至内置类)和不相关的 ABC 注册为“虚拟子类”——这些及其后代将被内置 issubclass() 函数视为注册 ABC 的子类,但注册 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
的行为,而无需在要考虑 ABC 子类的每个类上调用 register()。 (此类方法是从 ABC 的__subclasscheck__()
方法调用的。)此方法应返回
True
、False
或NotImplemented
。 如果它返回True
,则 子类 被视为此 ABC 的子类。 如果它返回False
,则 子类 不被视为此 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
抽象基类的一部分,但它不必在非抽象派生类中被覆盖。此处定义的 __subclasshook__() 类方法表示,任何在其 __dict__(或其基类之一的方法中)具有 __iter__() 方法的类,通过 __mro__ 列表访问)也被认为是
MyIterable
。最后,最后一行使
Foo
成为MyIterable
的虚拟子类,即使它没有定义 __iter__() 方法(它使用旧式可迭代协议,定义为__len__()
和__getitem__()
)。 请注意,这不会使get_iterator
作为Foo
的方法可用,因此单独提供。
它还提供以下装饰器:
- abc.abstractmethod(function)
指示抽象方法的装饰器。
使用这个装饰器需要类的元类是 ABCMeta 或者是从它派生的。 一个具有从 ABCMeta 派生的元类的类不能被实例化,除非它的所有抽象方法和属性都被覆盖。 可以使用任何正常的“超级”调用机制来调用抽象方法。
不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。 abstractmethod() 只影响使用常规继承派生的子类; 使用 ABC 的
register()
方法注册的“虚拟子类”不受影响。用法:
class C: __metaclass__ = ABCMeta @abstractmethod def my_abstract_method(self, ...): ...
笔记
与 Java 抽象方法不同,这些抽象方法可能有一个实现。 这个实现可以通过覆盖它的类的 super() 机制调用。 在使用协作多重继承的框架中,这可以用作超级调用的端点。
- abc.abstractproperty([fget[, fset[, fdel[, doc]]]])
内置 property() 的子类,表示抽象属性。
使用这个函数需要类的元类是 ABCMeta 或者是从它派生的。 一个具有从 ABCMeta 派生的元类的类不能被实例化,除非它的所有抽象方法和属性都被覆盖。 可以使用任何正常的“超级”调用机制来调用抽象属性。
用法:
class C: __metaclass__ = ABCMeta @abstractproperty def my_abstract_property(self): ...
这定义了一个只读属性; 您还可以使用“长”形式的属性声明来定义读写抽象属性:
class C: __metaclass__ = ABCMeta def getx(self): ... def setx(self, value): ... x = abstractproperty(getx, setx)
脚注
- 1
- C++ 程序员应该注意 Python 的虚拟基类概念与 C++ 的不同。