9.3.1 基本的序列和映射协议
序列和映射基本上是元素(item)的集合,要实现它们的基本行为(协议),不可变对象需要实现2个方法,而可变对象需要实现4个。
__len__(self):这个方法应返回集合包含的项数,对序列来说为元素个数,对映射来说为键值对数。如果__len__返回零(且没有实现覆盖这种行为的__nonzero__),对象在布尔上下文中将被视为假(就像空的列表、元组、字符串和字典一样)。
__getitem__(self, key):这个方法应返回与指定键相关联的值。对序列来说,键应该是0~n 1的整数(也可以是负数,这将在后面说明),其中n为序列的长度。对映射来说,键可以是任何类型。
__setitem__(self, key, value):这个方法应以与键相关联的方式存储值,以便以后能够使用__getitem__来获取。当然,仅当对象可变时才需要实现这个方法。
__delitem__(self, key):这个方法在对对象的组成部分使用__del__语句时被调用,应删除与key相关联的值。同样,仅当对象可变(且允许其项被删除)时,才需要实现这个方法。
对于这些方法,还有一些额外的要求。
对于序列,如果键为负整数,应从末尾往前数。换而言之, x[-n]应与x[len(x)-n]等效。
如果键的类型不合适(如对序列使用字符串键),可能引发TypeError异常。
对于序列,如果索引的类型是正确的,但不在允许的范围内,应引发IndexError异常。
要了解更复杂的接口和使用的抽象基类(Sequence),请参阅有关模块collections的文档。
下面来试一试,看看能否创建一个无穷序列。
def check_index(key):
"""
指定的键是否是可接受的索引?
键必须是非负整数,才是可接受的。如果不是整数,
将引发TypeError异常;如果是负数,将引发Index
Error异常(因为这个序列的长度是无穷的)
"""
if not isinstance(key, int):
raiseTypeError
if key
raise IndexError
class ArithmeticSequence:
def __init__(self, start=0, step=1):
"""
初始化这个算术序列
start -序列中的第一个值
step -两个相邻值的差
changed -一个字典,包含用户修改后的值
"""
self.start = start # 存储起始值
self.step = step # 存储步长值
self.changed = {} # 没有任何元素被修改
def __getitem__(self, key):
"""
从算术序列中获取一个元素
"""
check_index(key)
try:
return self.changed[key] # 修改过?
except KeyError: # 如果没有修改过,
return self.start + key * self.step # 就计算元素的值
def __setitem__(self, key, value):
"""
修改算术序列中的元素
"""
check_index(key)
self.changed[key] = value # 存储修改后的值
这些代码实现的是一个算术序列,其中任何两个相邻数字的差都相同。第一个值是由构造函数的参数start(默认为0)指定的,而相邻值之间的差是由参数step(默认为1)指定的。你允许用户修改某些元素,这是通过将不符合规则的值保存在字典changed中实现的。如果元素未被修改,就使用公式self.start + key * self.step来计算它的值。
下面的示例演示了如何使用这个类:
>>> s = ArithmeticSequence(1, 2)
9
>>> s[4] = 2
2
11
请注意,我要禁止删除元素,因此没有实现__del__:
>>> del s[4]
Traceback (most recent call last):
File "", line 1, in?
AttributeError: ArithmeticSequence instancehas no attribute '__delitem__'
另外,这个类没有方法__len__,因为其长度是无穷的。
如果所使用索引的类型非法,将引发TypeError异常;如果索引的类型正确,但不在允许的范围内(即为负数),将引发IndexError异常。
>>> s["four"]
Traceback (most recent call last):
File "", line 1, in?
File "arithseq.py", line 31, in__getitem__
check_index(key)
File "arithseq.py", line 10, incheckIndex
ifnot isinstance(key, int): raiseTypeError
TypeError
>>> s[-42]
Traceback (most recent call last):
File "", line 1, in?
File "arithseq.py", line 31, in__getitem__
check_index(key)
File "arithseq.py", line 11, incheckIndex
if key
IndexError
索引检查是由我为此编写的辅助函数check_index负责的。
领取专属 10元无门槛券
私享最新 技术干货