Python进阶:自定义对象实现切片功能
切片是 Python 中最迷人最强大最 Amazing 的语言特性(几乎没有之一),在《Python进阶:切片的误区与高级用法》中,我介绍了切片的基础用法、高级用法以及一些使用误区。这些内容都是基于原生的序列类型(如字符串、列表、元组......),那么,我们是否可以定义自己的序列类型并让它支持切片语法呢?更进一步,我们是否可以自定义其它对象(如字典)并让它支持切片呢?
1、魔术方法:__getitem__()
想要使自定义对象支持切片语法并不难,只需要在定义类的时候给它实现魔术方法 __getitem__()
即可。所以,这里就先介绍一下这个方法。
语法: object.__getitem__(self, key)
官方文档释义:Called to implement evaluation of self[key]. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the __getitem__()
method. If key is of an inappropriate type, TypeError may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), IndexError should be raised. For mapping types, if key is missing (not in the container), KeyError should be raised.
概括翻译一下:__getitem__()
方法用于返回参数 key 所对应的值,这个 key 可以是整型数值和切片对象,并且支持负数索引;如果 key 不是以上两种类型,就会抛 TypeError;如果索引越界,会抛 IndexError ;如果定义的是映射类型,当 key 参数不是其对象的键值时,则会抛 KeyError 。
2、自定义序列实现切片功能
接下来,我们定义一个简单的 MyList ,并给它加上切片功能。(PS:仅作演示,不保证其它功能的完备性)。
class MyList(): def __init__(self): self.data = [] def append(self, item): self.data.append(item) def __getitem__(self, key): print("key is : " + str(key)) return self.data[key] l = MyList() l.append("My") l.append("name") l.append("is") l.append("Python猫") print(l[3]) print(l[:2]) print(l['hi']) ### 输出结果: key is : 3 Python猫 key is : slice(None, 2, None) ['My', 'name'] key is : hi Traceback (most recent call last): ... TypeError: list indices must be integers or slices, not str
从输出结果来看,自定义的 MyList 既支持按索引查找,也支持切片操作,这正是我们的目的。
特别需要说明的是,此例中的 __getitem__()
方法会根据不同的参数类型而实现不同的功能(取索引位值或切片值),也会妥当地处理异常,所以并不需要我们再去写繁琐的处理逻辑。网上有不少学习资料完全是在误人子弟,它们会教你区分参数的不同类型,然后写一大段代码来实现索引查找和切片语法,简直是画蛇添足。下面的就是一个代表性的错误示例:
###略去其它代码#### def __getitem__(self, index): cls = type(self) if isinstance(index, slice): # 如果index是个切片类型,则构造新实例 return cls(self._components[index]) elif isinstance(index, numbers.Integral): # 如果index是个数,则直接返回 return self._components[index] else: msg = "{cls.__name__} indices must be integers" raise TypeError(msg.format(cls=cls))
3、自定义字典实现切片功能
切片是序列类型的特性,所以在上例中,我们不需要写切片的具体实现逻辑。但是,对于其它非序列类型的自定义对象,就得自己实现切片逻辑。以自定义字典为例(PS:仅作演示,不保证其它功能的完备性):
class MyDict(): def __init__(self): self.data = {} def __len__(self): return len(self.data) def append(self, item): self.data[len(self)] = item def __getitem__(self, key): if isinstance(key, int): return self.data[key] if isinstance(key, slice): slicedkeys = list(self.data.keys())[key] return {k: self.data[k] for k in slicedkeys} else: raise TypeError d = MyDict() d.append("My") d.append("name") d.append("is") d.append("Python猫") print(d[2]) print(d[:2]) print(d[-4:-2]) print(d['hi']) ### 输出结果: is {0: 'My', 1: 'name'} {0: 'My', 1: 'name'} Traceback (most recent call last): ... TypeError
上例的关键点在于将字典的键值取出,并对键值的列表做切片处理,其妙处在于,不用担心索引越界和负数索引,将字典切片转换成了字典键值的切片,最终实现目的。
4、小结
最后小结一下:本文介绍了__getitem__()
魔术方法,并用于实现自定义对象(以列表类型和字典类型为例)的切片功能,希望对你有所帮助。
参考阅读:
官方文档getitem用法:http://t.cn/EbzoZyp
Python切片赋值源码分析:http://t.cn/EbzSaoZ
PS:本公众号(Python猫)已开通读者交流群,详情请通过菜单栏中的“交流群”来了解。
-----------------
本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
详解 Java 11 新特性, Java高级程序员必备
Java 11新特性的详细解释。JDK 11已经于 2018年9月25日正式发布,那么Java 11主要包含哪些新特性呢? JDK 11是Java SE 11平台版本11的开源参考实现,由JSR 384在Java Community Process中指定。阿里巴巴是中国唯一的JCP委员会成员公司,参与Java规范制定。该版本的功能和时间表是通过JEP流程提出和跟踪的,并由JEP 2.0提案进行了修订。 使用JDK Release Process(JEP 3)生成发布。 1、Java11 主要新特性 详解 181:嵌套访问控制 Nest-Based Access Control详解:Java 11中引入了一个名为nest的新访问控制上下文,它与Java中的术语“嵌套类型”相关联。 它允许逻辑上属于同一代码实体的类,但是可以为特定的类文件进
- 下一篇
Java 基础总结
Java总结 jdk:Java的开发环境与部署环境 jre:Java的运行环境 Java数据类型分为:基本类型和引用类型 基本类型:① 整数类型 byteshortintlong默认值: 0 ② 字符类型 char默认值: 空格 ③ 浮点类型 floatdouble默认值: 0.0 ④ 布尔类型 boolean默认值: false 引用类型:① 类 ② 接口 ③数组 ④ null 类型 Java中除基本类型之外的类型都被称为引用类型,默认值为: null 八大基本数据类型: byte字节型1个字节8位-2^7~2^7-1 short短整型2个字节16位-2^15~2^15-1 int整型4个字节32位-2^31~2^31-1默认 long长整型8个字节64位-2^63~2^63-1使用时在数据最后加L/l float单精度浮点型4个字节32位使用时在数据最后加F/f double双精度浮点型8个字节64位默认 char字符型2个字节16位0~65535 boolean布尔型1个字节8位false true 可以给 char 型的变量直接赋 int 型的值,取值范...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Mario游戏-低调大师作品
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题