我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python进阶:自定义对象实现切片功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python进阶:自定义对象实现切片功能

2018-12-31 更新声明:切片系列文章本是分三篇写成,现已合并成一篇。合并后,修正了一些严重的错误(如自定义序列切片的部分),还对行文结构与章节衔接做了大量改动。原系列的单篇就不删除了,毕竟也是有单独成篇的作用。特此声明,请阅读改进版—— Python进阶:全面解读高级特性之切片!https://mp.weixin.qq.com/s/IRAjR-KHZBPEEkdiofseGQ

 

 

切片是 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 __iter__(self):
          return self
      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__() 魔术方法,并用于实现自定义对象(以列表类型和字典类型为例)的切片功能,希望对你有所帮助。

 

参考阅读:

Python进阶:切片的误区与高级用法

官方文档getitem用法:http://t.cn/EbzoZyp

Python切片赋值源码分析:http://t.cn/EbzSaoZ

 

PS:本公众号(Python猫)已开通读者交流群,详情请通过菜单栏中的“交流群”来了解。

 

-----------------

本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python进阶:自定义对象实现切片功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python进阶:自定义对象实现切片功能

2018-12-31 更新声明:切片系列文章本是分三篇写成,现已合并成一篇。合并后,修正了一些严重的错误(如自定义序列切片的部分),还对行文结构与章节衔接做了大量改动。原系列的单篇就不删除了,毕竟也是有单独成篇的作用。特此声明,请阅读改进版
2023-01-30

Android 实现自定义圆形进度条的功能

Android 实现自定义圆形进度条: Android 自定义view,在大多数项目中根据客户需求及用户的体验度来说,都要重新写控件的来展示漂亮的界面,这里就对圆形进度条说下如何实现。 绘制自定义的圆形进度条
2022-06-06

Android自定义View实现照片裁剪框与照片裁剪功能

本文所需要实现的就是这样一种有逼格的效果:右上角加了个图片框,按下确定可以裁剪正方形区域里的图片并显示在右上角。 实现思路: 1:首先需要自定义一个ZoomImageView来显示我们需要的图片,这个View需要让图片能够以合适的位置展现在
2022-06-06

Android自定义图片地图坐标功能的实现方法

本篇内容主要讲解“Android自定义图片地图坐标功能的实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Android自定义图片地图坐标功能的实现方法”吧!一、前言最近项目要求实现一个在自
2023-06-20

html+css实现自定义图片上传按钮功能的方法

小编给大家分享一下html+css实现自定义图片上传按钮功能的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!普通的input[type=‘file
2023-06-09

android开发中使用view实现自定义一个进度条功能

今天就跟大家聊聊有关android开发中使用view实现自定义一个进度条功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、自定义属性:
2023-05-31

怎么进行Vue自定义复制指令v-copy功能的实现

这篇文章给大家介绍怎么进行Vue自定义复制指令v-copy功能的实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。使用自定义指令创建一个点击复制文本功能1. 创建v-copy.js文件import Vue from "
2023-06-26

Android编程基于自定义View实现绚丽的圆形进度条功能示例

本文实例讲述了Android编程基于自定义View实现绚丽的圆形进度条功能。分享给大家供大家参考,具体如下: 本文包含两个组件,首先上效果图: 1.ProgressBarView1(支持拖动):2.ProgressBarView2(不同进度
2022-06-06

Android 自定义ListView实现QQ空间界面(说说内包含图片、视频、点赞、评论、转发功能)

前端时间刚好需要做一个类似于QQ空间的社区分享功能,说说内容包含文字(话题、内容)、视频、图片,还需包含点赞,评论,位置信息等功能。 就采用LIstview做了一个,先来看下效果,GIF太大,CSDN传不了,请移步Gitee连接:GIF效果
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录