3.3.7. 模拟容器类型
可以定义下列方法来实现容器对象。 容器通常属于序列(如列表或元组)或映射(如字典),但也存在其他形式的容器。 前几个方法集被用于模拟序列或是模拟映射;两者的不同之处在于序列允许的键应为整数 k 且 0 <= k < N
其中 N 是序列或定义指定区间的项的切片对象的长度。 此外还建议让映射提供 keys()
, values()
, items()
, get()
, clear()
, setdefault()
, pop()
, popitem()
, copy()
以及 update()
等方法,它们的行为应与 Python 标准字典对象的相应方法类似。 此外 collections.abc
模块提供了一个 MutableMapping
抽象基类以便根据由 __getitem__()
, __setitem__()
, __delitem__()
, 和 keys()
组成的基本集来创建所需的方法。 可变序列还应像 Python 标准列表对象那样提供 append()
, count()
, index()
, extend()
, insert()
, pop()
, remove()
, reverse()
和 sort()
等方法。 最后,序列类型还应通过定义下文描述的 __add__()
, __radd__()
, __iadd__()
, __mul__()
, __rmul__()
和 __imul__()
等方法来实现加法(指拼接)和乘法(指重复);它们不应定义其他数值运算符。 此外还建议映射和序列都实现 __contains__()
方法以允许高效地使用 in
运算符;对于映射,in
应该搜索映射的键;对于序列,则应搜索其中的值。 另外还建议映射和序列都实现 __iter__()
方法以允许高效地迭代容器中的条目;对于映射,__iter__()
应当迭代对象的键;对于序列,则应当迭代其中的值。
object.__len__
(self)
调用此方法以实现内置函数 len()
。应该返回对象的长度,以一个 >=
0 的整数表示。此外,如果一个对象未定义 __bool__()
方法而其 __len__()
方法返回值为零,则在布尔运算中会被视为假值。
CPython implementation detail: 在 CPython 中,要求长度最大为 sys.maxsize
。如果长度大于 sys.maxsize
则某些特性 (例如 len()
) 可能会引发 OverflowError
。要通过真值检测来防止引发 OverflowError
,对象必须定义 __bool__()
方法。
object.__length_hint__
(self)
调用此方法以实现 operator.length_hint()
。 应该返回对象长度的估计值(可能大于或小于实际长度)。 此长度应为一个 >=
0 的整数。 返回值也可以为 NotImplemented
,这会被视作与 __length_hint__
方法完全不存在时一样处理。 此方法纯粹是为了优化性能,并不要求正确无误。
3.4 新版功能.
注解
切片是通过下述三个专门方法完成的。以下形式的调用
a[1:2] = b
会为转写为
a[slice(1, 2, None)] = b
其他形式以此类推。略去的切片项总是以 None
补全。
object.__getitem__
(self, key)
调用此方法以实现 self[key]
的求值。对于序列类型,接受的键应为整数和切片对象。请注意负数索引(如果类想要模拟序列类型)的特殊解读是取决于 __getitem__()
方法。如果 key 的类型不正确则会引发 TypeError
异常;如果为序列索引集范围以外的值(在进行任何负数索引的特殊解读之后)则应引发 IndexError
异常。对于映射类型,如果 key 找不到(不在容器中)则应引发 KeyError
异常。
注解
for
循环在有不合法索引时会期待捕获 IndexError
以便正确地检测到序列的结束。
object.__setitem__
(self, key, value)
调用此方法以实现向 self[key]
赋值。注意事项与 __getitem__()
相同。为对象实现此方法应该仅限于需要映射允许基于键修改值或添加键,或是序列允许元素被替换时。不正确的 key 值所引发的异常应与 __getitem__()
方法的情况相同。
object.__delitem__
(self, key)
调用此方法以实现 self[key]
的删除。注意事项与 __getitem__()
相同。为对象实现此方法应该权限于需要映射允许移除键,或是序列允许移除元素时。不正确的 key 值所引发的异常应与 __getitem__()
方法的情况相同。
object.__missing__
(self, key)
此方法由 dict
.__getitem__()
在找不到字典中的键时调用以实现 dict 子类的 self[key]
。
object.__iter__
(self)
此方法在需要为容器创建迭代器时被调用。此方法应该返回一个新的迭代器对象,它能够逐个迭代容器中的所有对象。对于映射,它应该逐个迭代容器中的键。
迭代器对象也需要实现此方法;它们需要返回对象自身。有关迭代器对象的详情请参看 迭代器类型 一节。
object.__reversed__
(self)
此方法(如果存在)会被 reversed()
内置函数调用以实现逆向迭代。它应当返回一个新的以逆序逐个迭代容器内所有对象的迭代器对象。
如果未提供 __reversed__()
方法,则 reversed()
内置函数将回退到使用序列协议 (__len__()
和 __getitem__()
)。支持序列协议的对象应当仅在能够提供比 reversed()
所提供的实现更高效的实现时才提供 __reversed__()
方法。
成员检测运算符 (in
和 not in
) 通常以对容器进行逐个迭代的方式来实现。 不过,容器对象可以提供以下特殊方法并采用更有效率的实现,这样也不要求对象必须为可迭代对象。
object.__contains__
(self, item)
调用此方法以实现成员检测运算符。如果 item 是 self 的成员则应返回真,否则返回假。对于映射类型,此检测应基于映射的键而不是值或者键值对。
对于未定义 __contains__()
的对象,成员检测将首先尝试通过 __iter__()
进行迭代,然后再使用 __getitem__()
的旧式序列迭代协议,参看 语言参考中的相应部分。