collections.abc
— 容器的抽象基类¶
3.3 版新增: 此模块之前是 collections
模块的一部分。
此模块提供了 抽象基类,可用于测试类是否提供了特定的接口;例如,它是否 可哈希 或它是否是 映射。
对接口进行 issubclass()
或 isinstance()
测试可以通过以下三种方式之一进行。
1) 新编写的类可以直接从其中一个抽象基类继承。该类必须提供所需的抽象方法。其余的混合方法来自继承,如果需要,可以重写。可以根据需要添加其他方法
class C(Sequence): # Direct inheritance
def __init__(self): ... # Extra method not required by the ABC
def __getitem__(self, index): ... # Required abstract method
def __len__(self): ... # Required abstract method
def count(self, value): ... # Optionally override a mixin method
>>> issubclass(C, Sequence)
True
>>> isinstance(C(), Sequence)
True
2) 现有类和内置类可以注册为 ABC 的“虚拟子类”。这些类应定义完整的 API,包括所有抽象方法和所有混合方法。这允许用户依赖 issubclass()
或 isinstance()
测试来确定是否支持完整的接口。此规则的例外情况是针对从 API 的其余部分自动推断出的方法
class D: # No inheritance
def __init__(self): ... # Extra method not required by the ABC
def __getitem__(self, index): ... # Abstract method
def __len__(self): ... # Abstract method
def count(self, value): ... # Mixin method
def index(self, value): ... # Mixin method
Sequence.register(D) # Register instead of inherit
>>> issubclass(D, Sequence)
True
>>> isinstance(D(), Sequence)
True
在此示例中,类 D
不需要定义 __contains__
、__iter__
和 __reversed__
,因为 in 运算符、迭代 逻辑和 reversed()
函数会自动回退到使用 __getitem__
和 __len__
。
3) 一些简单的接口可以通过所需方法的存在直接识别(除非这些方法已设置为 None
)
class E:
def __iter__(self): ...
def __next__(self): ...
>>> issubclass(E, Iterable)
True
>>> isinstance(E(), Iterable)
True
复杂的接口不支持最后一种技术,因为接口不仅仅是方法名称的存在。接口指定了方法之间的语义和关系,这些语义和关系不能仅从特定方法名称的存在来推断。例如,知道一个类提供了 __getitem__
、__len__
和 __iter__
不足以区分 Sequence
和 Mapping
。
集合抽象基类¶
collections 模块提供了以下 ABC
ABC |
继承自 |
抽象方法 |
混合方法 |
---|---|---|---|
|
|||
|
|||
|
|||
|
|
||
|
|||
|
|
||
|
|||
|
|||
|
|||
|
|
||
|
继承自 |
||
|
继承自 |
||
|
|
||
|
继承自 |
||
|
|
||
|
继承自 |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
||
|
|||
|
|
||
|
|
||
|
脚注
集合抽象基类 – 详细说明¶
- class collections.abc.Container¶
提供
__contains__()
方法的类的抽象基类。
- class collections.abc.Hashable¶
提供
__hash__()
方法的类的抽象基类。
- class collections.abc.Callable¶
针对提供
__call__()
方法的类的 ABC。
- class collections.abc.Iterable¶
针对提供
__iter__()
方法的类的 ABC。检查
isinstance(obj, Iterable)
可以检测注册为Iterable
的类或具有__iter__()
方法的类,但它无法检测使用__getitem__()
方法进行迭代的类。确定对象是否为 可迭代 的唯一可靠方法是调用iter(obj)
。
- class collections.abc.Collection¶
针对可确定大小的可迭代容器类的 ABC。
3.6 版新增。
- class collections.abc.Iterator¶
针对提供
__iter__()
和__next__()
方法的类的 ABC。另请参阅 迭代器 的定义。
- class collections.abc.Reversible¶
针对也提供
__reversed__()
方法的可迭代类的 ABC。3.6 版新增。
- class collections.abc.Generator¶
针对实现 PEP 342 中定义的协议的 生成器 类的 ABC,该协议使用
send()
、throw()
和close()
方法扩展了 迭代器。3.5 版新增。
- class collections.abc.Sequence¶
- class collections.abc.MutableSequence¶
- class collections.abc.ByteString¶
针对只读和可变 序列 的 ABC。
实现说明:某些混入方法,例如
__iter__()
、__reversed__()
和index()
,会重复调用底层的__getitem__()
方法。因此,如果__getitem__()
是以恒定访问速度实现的,则混入方法将具有线性性能;但是,如果底层方法是线性的(就像链表那样),则混入方法将具有二次性能,并且可能需要被覆盖。在 3.5 版更改: index() 方法添加了对 *stop* 和 *start* 参数的支持。
自 3.12 版弃用,将在 3.14 版移除:
ByteString
ABC 已被弃用。如果用于类型提示,建议使用联合类型,例如bytes | bytearray
或collections.abc.Buffer
。如果用作 ABC,建议使用Sequence
或collections.abc.Buffer
。
- class collections.abc.MappingView¶
- class collections.abc.ItemsView¶
- class collections.abc.KeysView¶
- class collections.abc.ValuesView¶
针对映射、项、键和值 视图 的 ABC。
- class collections.abc.Awaitable¶
针对 可等待 对象的 ABC,可以在
await
表达式中使用。自定义实现必须提供__await__()
方法。协程 对象和
Coroutine
ABC 的实例都是此 ABC 的实例。注意
在 CPython 中,基于生成器的协程(用
@types.coroutine
装饰的 生成器)是*可等待对象*,即使它们没有__await__()
方法。对它们使用isinstance(gencoro, Awaitable)
将返回False
。使用inspect.isawaitable()
来检测它们。3.5 版新增。
- class collections.abc.Coroutine¶
与 协程 兼容的类的 ABC。它们实现了以下方法,这些方法在 协程对象 中定义:
send()
、throw()
和close()
。自定义实现还必须实现__await__()
。所有Coroutine
实例也是Awaitable
的实例。注意
在 CPython 中,基于生成器的协程(用
@types.coroutine
装饰的 生成器)是*可等待对象*,即使它们没有__await__()
方法。对它们使用isinstance(gencoro, Coroutine)
将返回False
。使用inspect.isawaitable()
来检测它们。3.5 版新增。
- class collections.abc.Buffer¶
提供
__buffer__()
方法的类的 ABC,实现了 缓冲区协议。请参阅 PEP 688。3.12 版新增。
示例和方法¶
ABC 允许我们询问类或实例是否提供特定功能,例如
size = None
if isinstance(myvar, collections.abc.Sized):
size = len(myvar)
一些 ABC 也可以用作混入类,从而更容易开发支持容器 API 的类。例如,要编写一个支持完整 Set
API 的类,只需提供三个底层抽象方法:__contains__()
、__iter__()
和 __len__()
。ABC 提供了其余的方法,例如 __and__()
和 isdisjoint()
class ListBasedSet(collections.abc.Set):
''' Alternate set implementation favoring space over speed
and not requiring the set elements to be hashable. '''
def __init__(self, iterable):
self.elements = lst = []
for value in iterable:
if value not in lst:
lst.append(value)
def __iter__(self):
return iter(self.elements)
def __contains__(self, value):
return value in self.elements
def __len__(self):
return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2 # The __and__() method is supported automatically
关于使用 Set
和 MutableSet
作为混入类的注意事项
由于某些集合操作会创建新的集合,因此默认的混入方法需要一种从 可迭代对象 创建新实例的方法。假定类构造函数的签名形式为
ClassName(iterable)
。该假设被分解为一个名为_from_iterable()
的内部classmethod
,它调用cls(iterable)
来生成一个新的集合。如果在具有不同构造函数签名的类中使用Set
混入类,则需要使用可以从可迭代参数构造新实例的类方法或常规方法覆盖_from_iterable()
。要覆盖比较(可能是为了速度,因为语义是固定的),请重新定义
__le__()
和__ge__()
,然后其他操作将自动随之进行。Set
混入类提供了一个_hash()
方法来计算集合的哈希值;但是,__hash__()
没有定义,因为并非所有集合都是 可哈希的 或不可变的。要使用混入类添加集合可哈希性,请同时继承Set()
和Hashable()
,然后定义__hash__ = Set._hash
。
另请参阅
OrderedSet 配方,以获取基于
MutableSet
构建的示例。