Python元素访问

1.基本序列和映射协议

在Python中,协议通常指的是规范行为的原则。类似于接口。协议指定哪些方法以及这些方法应做什么。
Python通常只要求对象遵循的特定的协议。所以要成为序列,遵循序列协议就可以了。
序列和映射都是元素的集合,要实现它们的基本行为,不可变对象需要实现两个方法,可变对象需要实现四个方法。
1_len_(self):返回集合包含的项数,对序列来说为元素个体,对映射来说为键—值对数。如果_len_返回零(且没有实现覆盖这种行为的_nonzero_),对象在布尔上下文中被视为假(类似于空的列表、元组、字符串、字典一样)。
2_getitem_(self,key):返回和指定值相关联的值。对序列来说,键应该是0—(n-1)的整数(负数也可以),n为序列的长度。对映射来说,键可以是任何类型。
3_setitem_(self, key,value):以与键相关联的方式储存值,以便以后能够使用_getitem_获取。仅当对象可变时才需要实现这个方法。
4_delitem_(self,key):在对对象的组成部分使用_del_时调用。应删除与key有关的值。仅当对象可变时才需要实现这个方法。
对于这些方法,还有一些额外的要求。

  1. 对于序列,如果键为负数,应从末尾往前数。x[-n]和x[len(x)-n]等效
  2. 若键的类型不合适,应引发TypeError异常(如对序列使用字符串键)
  3. 对于序列,若索引的类型正确。但不在允许的范围内,应引发IndexError异常。
def check_index(key):
	if not isinstance(key,int):raise TypeError
	if key<0 :raise IndexError
class ArithmeticSequqnce:
	def _init_(self,start=0,step=1):
		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来计算它的值。

>>>a=ArithmeticSequqnce(1,2)
>>>a[4]
9
>>>a[4]=2
>>>a[4]
2
>>>a[5]
11 			#禁止删除元素,没有实现_del_
>>>del a[4]
Traceback(most recent call last):
  File"<stdin>",line 1,in ?
AttributError:ArithmeticSequqnce instance has no attribute '_delitm_'
#没有_len_,因为长度是无限的。
>>>a['four']
Traceback(most recent call last):
  File"<stdin>",line 1,in ?
  File"arithseq.py",line 31, in _getitem_
  	check_index(key)
  File"arithseq.py",line 10, in checkIndex
  	if not isinstance(key,int):raise TypeError
TypeError
>>>a[-10]
Traceback(most recent call last):
  File"<stdin>",line 1,in ?
  File"arithseq.py",line 31, in _getitem_
  	check_index(key)
  File"arithseq.py",line 11, in checkIndex
  	if key<0:raise IndexError
IndexError

索引检查由辅助函数check_index负责

2.从list、dict、str派生

在标准库中模块collections提供了抽象和具体的基类,但你也可以继承内置类型。因此,如果要实现一行为类似于内置列表的序列类型,可直接继承list。

#示例——一个带访问计数器的列表。
class CounterList(list);
	def dei5.Cghe 2-8s)
		super().___init
		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_并不能保证一定会捕捉用户的访问操作,因为还有其他访问列表内容的方式
下面演示了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
0
>>>cl[4]+cl[2]
9
>>>cl.counter
2

如你所见,CounterList的行为在大多数方面都类似于列表,但是它有一个counter属性(初始值为零)。每当你访问列表元素时,这个属性都加1。执行加法运算cl[4]+cl[2]后,counter的值递增了两次,变为了2.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值