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-operator、 iteration 逻辑和 reversed()
函数自动回落到使用 __getitem__
和 __len__
。
3)一些简单的接口可以通过所需方法的存在直接识别(除非这些方法被设置为 None
):
class E:
def __iter__(self): ...
def __next__(next): ...
>>> issubclass(E, Iterable)
True
>>> isinstance(E(), Iterable)
True
复杂的接口不支持最后一种技术,因为接口不仅仅是方法名称的存在。接口指定了语义和方法之间的关系,这不能仅仅从特定方法名称的存在中推断出来。例如,知道一个类提供了 __getitem__
、__len__
和 __iter__
,并不足以区分 Sequence
和 Mapping
。
3.9 新版功能: 这些抽象类现在支持 []
。参见 GenericAlias 类型 和 PEP 585。
容器抽象基类¶
这个容器模块提供了以下 ABCs:
抽象基类 |
继承自 |
抽象方法 |
Mixin 方法 |
---|---|---|---|
|
|||
|
|||
|
|||
|
|
||
|
|||
|
|
||
|
|||
|
|||
|
|||
|
|
||
|
继承自 |
||
|
继承自 |
||
|
|
||
|
继承自 |
||
|
|
||
|
继承自 |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|
||
|
|||
|
|
||
|
|
脚注
容器抽象基类 – 详细描述¶
- class collections.abc.Container¶
提供了
__contains__()
方法的抽象基类。
- class collections.abc.Hashable¶
提供了
__hash__()
方法的抽象基类。
- class collections.abc.Sized¶
提供了
__len__()
方法的抽象基类。
- class collections.abc.Callable¶
提供了
__call__()
方法的抽象基类。
- class collections.abc.Iterable¶
提供了
__iter__()
方法的抽象基类。使用
isinstance(obj, Iterable)
可以检测一个类是否已经注册到了Iterable
或者实现了__iter__()
函数,但是无法检测这个类是否能够使用__getitem__()
方法进行迭代。检测一个对象是否是 iterable 的唯一可信赖的方法是调用iter(obj)
。
- class collections.abc.Collection¶
集合了 Sized 和 Iterable 类的抽象基类。
3.6 新版功能.
- class collections.abc.Iterator¶
提供了
__iter__()
和__next__()
方法的抽象基类。参见 iterator 的定义。
- class collections.abc.Reversible¶
为可迭代类提供了
__reversed__()
方法的抽象基类。3.6 新版功能.
- class collections.abc.Generator¶
生成器类,实现了 PEP 342 中定义的协议,继承并扩展了迭代器,提供了
send()
,throw()
和close()
方法。参见 generator 的定义。3.5 新版功能.
- class collections.abc.Sequence¶
- class collections.abc.MutableSequence¶
- class collections.abc.ByteString¶
只读且可变的序列 sequences 的抽象基类。
实现笔记:一些混入(Maxin)方法比如
__iter__()
,__reversed__()
和index()
会重复调用底层的__getitem__()
方法。因此,如果实现的__getitem__()
是常数级访问速度,那么相应的混入方法会有一个线性的表现;然而,如果底层方法是线性实现(例如链表),那么混入方法将会是平方级的表现,这也许就需要被重构了。在 3.5 版更改: index() 方法支持 stop 和 start 参数。
- class collections.abc.MappingView¶
- class collections.abc.ItemsView¶
- class collections.abc.KeysView¶
- class collections.abc.ValuesView¶
映射及其键和值的视图 views 的抽象基类。
- class collections.abc.Awaitable¶
为可等待对象 awaitable 提供的类,可以被用于
await
表达式中。习惯上必须实现__await__()
方法。协程 对象和
Coroutine
ABC 的实例都是这个 ABC 的实例。备注
In CPython, generator-based coroutines (generators decorated with
types.coroutine()
) are awaitables, even though they do not have an__await__()
method. Usingisinstance(gencoro, Awaitable)
for them will returnFalse
. Useinspect.isawaitable()
to detect them.3.5 新版功能.
- class collections.abc.Coroutine¶
用于协程兼容类的抽象基类。实现了如下定义在 协程对象: 里的方法:
send()
,throw()
和close()
。通常的实现里还需要实现__await__()
方法。所有的Coroutine
实例都必须是Awaitable
实例。参见 coroutine 的定义。备注
在 CPython 中,基于生成器的 coroutine(用
types.coroutine()
装饰的生成器)是 awaitables,尽管它们没有__await__()
方法。对它们使用isinstance(gencoro, Coroutine)
将返回False
。使用inspect.isawaitable()
来检测它们。3.5 新版功能.
- class collections.abc.AsyncIterable¶
提供了
__aiter__
方法的抽象基类。参见 asynchronous iterable 的定义。3.5 新版功能.
- class collections.abc.AsyncIterator¶
提供了
__aiter__
和__anext__
方法的抽象基类。参见 asynchronous iterator 的定义。3.5 新版功能.
Examples and Recipes¶
ABC 允许我们询问类或实例是否提供特定的功能,例如:
size = None
if isinstance(myvar, collections.abc.Sized):
size = len(myvar)
有些抽象基类也可以用作混入类(mixin),这可以更容易地开发支持容器 API 的类。例如,要写一个支持完整 Set
API 的类,只需要提供下面这三个方法: __contains__()
, __iter__()
和 __len__()
。抽象基类会补充上其余的方法,比如 __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()
的内部类方法,该方法会调用cls(iterable)
来产生一个新集合。 如果Set
混入类在具有不同构造器签名的类中被使用,你将需要通过类方法或常规方法来重载_from_iterable()
,以便基于可迭代对象参数来构造新的实例。重载比较符时时(想必是为了速度,因为其语义都是固定的),只需要重定义
__le__()
和__ge__()
函数,然后其他的操作会自动跟进。混入集合类
Set
提供了一个_hash()
方法为集合计算哈希值,然而,__hash__()
函数却没有被定义,因为并不是所有集合都是可哈希并且不可变的。为了使用混入类为集合添加哈希能力,可以同时继承Set()
和Hashable()
类,然后定义__hash__ = Set._hash
。
参见
OrderedSet recipe 是基于
MutableSet
构建的一个示例。