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

 更新时间:2019年01月07日 11:08:49   作者:豌豆花下猫  
这篇文章主要介绍了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__() 魔术方法,并用于实现自定义对象(以列表类型和字典类型为例)的切片功能,希望对你有所帮助。也希望大家多多支持脚本之家。

相关文章

  • 由浅入深讲解python中的yield与generator

    由浅入深讲解python中的yield与generator

    这篇文章主要由浅入深讲解了python中yield与generator的相关资料,文中介绍的非常详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-04-04
  • 使用python 获取进程pid号的方法

    使用python 获取进程pid号的方法

    这篇文章主要介绍了使用python 获取进程pid号的方法,需要的朋友可以参考下
    2014-03-03
  • pytorch DataLoaderj基本使用方法详解

    pytorch DataLoaderj基本使用方法详解

    这篇文章主要为大家介绍了pytorch DataLoaderj基本使用方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • python 平衡二叉树实现代码示例

    python 平衡二叉树实现代码示例

    这篇文章主要介绍了python 平衡二叉树实现代码示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • python线程池的四种好处总结

    python线程池的四种好处总结

    在本篇文章里小编给大家整理的是一篇关于python线程池的四种好处归纳内容,有兴趣的朋友们可以学习下。
    2021-04-04
  • Python中requests库的基本概念与具体使用方法

    Python中requests库的基本概念与具体使用方法

    requests库是用python编写的基于urllib,requests唯一的一个非转基因的Python HTTP库,下面这篇文章主要给大家介绍了关于Python中requests库的基本概念与具体使用方法,需要的朋友可以参考下
    2022-08-08
  • 初步介绍Python中的pydoc模块和distutils模块

    初步介绍Python中的pydoc模块和distutils模块

    这篇文章主要介绍了Python中的pydoc模块和distutils模块,本文来自于IBM官方开发者技术文档,需要的朋友可以参考下
    2015-04-04
  • python中pyqtgraph知识点总结

    python中pyqtgraph知识点总结

    在本篇文章里小编给大家整理的是一篇关于python中pyqtgraph知识点总结内容,有兴趣的朋友们可以学习下。
    2021-01-01
  • Python文件的读写和异常代码示例

    Python文件的读写和异常代码示例

    这篇文章主要介绍了Python文件的读写和异常代码示例,首先分享了文件读写的简单方法,然后略为详细地介绍了Python异常的相关内容,不足之处,欢迎补充。
    2017-10-10
  • python 函数中的参数类型

    python 函数中的参数类型

    thon中函数的参数类型比较丰富,比如我们经常见到*args和**kwargs作为参数。今天给大家介绍python 函数中的参数类型,需要的朋友可以参考下
    2020-02-02

最新评论