9.3.2 从 list、 dict 和 str 派生
基本的序列/映射协议指定的4个方法能够让你走很远,但序列还有很多其他有用的魔法方法和普通方法,其中包括将在9.6节介绍的方法__iter__。要实现所有这些方法,不仅工作量大,而且难度不小。如果只想定制某种操作的行为,就没有理由去重新实现其他所有方法。这就是程序员的懒惰(也是常识)。
那么该如何做呢?“咒语”就是继承。在能够继承的情况下为何去重新实现呢?在标准库中,模块collections提供了抽象和具体的基类,但你也可以继承内置类型。因此,如果要实现一种行为类似于内置列表的序列类型,可直接继承list。
来看一个简单的示例——一个带访问计数器的列表。
class CounterList(list):
def __init__(self, *args):
super().__init__(*args)
self.counter = 0
def __getitem__(self, index):
self.counter += 1
return super(CounterList, self).__getitem__(index)
CounterList类深深地依赖于其超类(list)的行为。 CounterList没有重写的方法(如append、 extend、 index等)都可直接使用。在两个被重写的方法中,使用super来调用超类的相应方法,并添加了必要的行为:初始化属性counter(在__init__中)和更新属性counter(在__getitem__中)。
注意 重写__getitem__并不能保证一定会捕捉用户的访问操作,因为还有其他访问列表内容的方式,如通过方法pop。
下面的示例演示了CounterList的可能用法:
>>> cl = CounterList(range(10))
>>> cl
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> cl.reverse()
>>> cl
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del cl[3:6]
>>> cl[9, 8, 7, 3, 2, 1, 0]
>>> cl.counter
>>> cl[4] + cl[2]
9
>>> cl.counter
2
如你所见, CounterList的行为在大多数方面都类似于列表,但它有一个counter属性(其初始值为)。每当你访问列表元素时,这个属性的值都加1。执行加法运算cl[4] + cl[2]后,counter的值递增两次,变成了2。
领取专属 10元无门槛券
私享最新 技术干货