• 3.3.7. 模拟容器类型

    3.3.7. 模拟容器类型

    可以定义下列方法来实现容器对象。 容器通常属于序列(如列表或元组)或映射(如字典),但也存在其他形式的容器。 前几个方法集被用于模拟序列或是模拟映射;两者的不同之处在于序列允许的键应为整数 k0 <= 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 新版功能.

    注解

    切片是通过下述三个专门方法完成的。以下形式的调用

    1. a[1:2] = b

    会为转写为

    1. 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() 方法。

    成员检测运算符 (innot in) 通常以对容器进行逐个迭代的方式来实现。 不过,容器对象可以提供以下特殊方法并采用更有效率的实现,这样也不要求对象必须为可迭代对象。

    • object.contains(self, item)
    • 调用此方法以实现成员检测运算符。如果 itemself 的成员则应返回真,否则返回假。对于映射类型,此检测应基于映射的键而不是值或者键值对。

    对于未定义 contains() 的对象,成员检测将首先尝试通过 iter() 进行迭代,然后再使用 getitem() 的旧式序列迭代协议,参看 语言参考中的相应部分。