切片是Python中最迷人、最强大、最神奇的语言特性(几乎没有)。在《Python进阶:切片的误区与高级用法》中介绍了切片的基本用法和高级用法以及一些误区。这些内容都是基于原生的序列类型(比如字符串、列表、元组……),那么,我们能不能定义自己的序列类型,让它支持切片语法呢?更进一步,我们能不能自定义其他对象(比如字典),让它支持切片呢?1.魔术方法:__getitem__()让自定义对象支持切片语法并不难,只需要在定义类的时候为其实现魔术方法__getitem__()即可。所以,这里首先介绍一下这个方法。语法:object.__getitem__(self,key)官方文档解读:调用实现对self[key]的求值。对于序列类型,接受的键应该是整数和切片对象。请注意,负索引的特殊解释(如果类希望模拟序列类型)取决于__getitem__()方法。如果键的类型不合适,可能会引发TypeError;如果值超出序列的索引集(在对负值进行任何特殊解释之后),则应引发IndexError。对于映射类型,如果缺少键(不在容器中),则应引发KeyError。通用翻译:__getitem__()方法用于返回参数key对应的值,可以是整型Value和slice对象,支持负索引;如果key不是以上两种类型,会抛出TypeError;如果索引越界,将抛出IndexError;如果定义的是映射类型,当key参数不是其对象的key值时,就会抛出KeyError。2.自定义sequence实现切片功能接下来,我们定义一个简单的MyList,并为其添加切片功能。(PS:仅作演示,不保证其他功能的完整性)。类MyList():def__init__(self):自我。data=[]defappend(self,item):self.数据。append(item)def__getitem__(self,key):print("keyis:"+str(key))returnself.data[key]l=MyList()l.append("我的")l.append("函数name")l.append("is")l.append("Python编程学习圈")print(l[3])print(l[:2])print(l['hi'])###输出result:keyis:3Pythonprogramminglearningcirclekeyis:slice(None,2,None)['My','name']keyis:hiTraceback(mostrecentcalllast):...TypeError:列表索引必须是整数orslices,notstr从输出结果来看,自定义的MyList支持索引查找,也支持切片操作,这正是我们想要的。特别是本例中的__getitem__()方法会根据不同的参数类型实现不同的功能(取索引位值或分片值),同时也会妥善处理异常,所以我们不需要再去写繁琐的处理逻辑。网上有很多学习资料,完全是误导。他们会教你区分不同类型的参数,然后写一大段代码实现索引搜索和切片语法,简直画蛇添足。下面是一个有代表性的错误示例:###Omitothercode####def__getitem__(self,index):cls=type(self)ifisinstance(index,slice):#如果index是slice类型,则构造anewinstancereturncls(self._components[index])elifisinstance(index,numbers.Integral):#如果index是数字,直接returnreturnself._components[index]else:msg="{cls.__name__}indicesmustbeintegers"raiseTypeError(msg.format(cls=cls))3.自定义字典实现切片功能切片是序列类型的特性,所以在上面的例子中,我们不需要写切片的具体实现逻辑.但是,对于其他非串行类型的自定义对象,则需要自己实现切片逻辑。以自定义字典为例(PS:只是为了演示,不保证其他功能的完整性):classMyDict():def__init__(self):self.data={}def__len__(self):returnlen(self.data)defappend(self,item):self.data[len(self)]=itemdef__getitem__(self,key):ifisinstance(key,int):返回自我。data[key]ifisinstance(key,slice):slicedkeys=list(self.data.keys())[key]返回{k:self.data[k]forkinslicedkeys}else:raiseTypeErrord=MyDict()d.追加(“我的”)d。append("name")d.append("is")d.append("Python编程学习圈")print(d[2])print(d[:2])print(d[-4:-2])print(d['hi'])###outputresult:is{0:'My',1:'name'}{0:'My',1:'name'}Traceback(最近调用最后):...TypeError上面例子的关键点是取出字典的键值,对键值列表进行分片。妙处在于将字典切片转化为字典键值,不用担心索引越界和负索引切片,最终达到目的。4.小结本文介绍了__getitem__()魔术方法,用于实现自定义对象的切片功能(以列表类型和字典类型为例),希望对您有所帮助。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,送“J”免费领取,每日干货分享
