本文介绍如何自定义迭代器,涉及到类的运算符重载,包括__getitem__的索引迭代,以及__iter____next____contains__,如果不了解这些知识可跳过本文。

索引迭代方式

索引取值和分片取值

元组、列表、字典、集合、字符串都支持索引取值操作和分片操作。

>>> L = [11,21,31,41]
>>> L[0]
11
>>> L[0:2]
[11, 21]

分片操作实际上将一个slice对象当作索引位传递给序列,然后以索引取值的方式取得所需元素。

>>> L[0:2]
[11, 21]>>> L[slice(0,2)]
[11, 21]

slice对象由slice()函数创建,它有3个参数:起始索引位、结束索引位、步进值。例如:

>>> slice(0,2)
slice(0, 2, None)

__getitem__

列表、元组等序列之所以可以索引取值、分片取值,是因为它们实现了__getitem__方法。

例如:

>>> hasattr(list,"__getitem__")
True
>>> hasattr(tuple,"__getitem__")
True
>>> hasattr(dict,"__getitem__")
True
>>> hasattr(str,"__getitem__")
True

如果自定义类并实现__getitem__方法,它们会重载索引取值:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class cls:def __getitem__(self, index):print("getitem index", index)return index * 2>>> c = cls()
>>> c[1]
getitem index 1
2
>>> c[2]
getitem index 2
4
>>> c[3]
getitem index 3
6

上面的自定义类只支持索引取值,不支持分片取值。因为__getitem__中没有编写索引取值的方式,也就不支持传递slice对象来进行分片取值。

分片和__getitem__

如果想要__getitem__支持分片取值,需要在__getitem__中使用索引取值的方式,以便支持slice对象作为索引。

下面是一个简单的支持分片操作的自定义类:

class cls:def __init__(self,data):self._data = datadef __getitem__(self,index):print("getitem:",index)return self._data[index]>>> c = cls([1,2,3,4])
>>> c[1]
getitem: 1
2
>>> c[0:2]
getitem: slice(0, 2, None)
[1, 2]

__setitem____delitem__

如果想要索引或者分片赋值,那么会调用__setitem__()方法,如果想要删除索引值或分片值,会调用__delitem__()方法。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class cls:def __init__(self,data):self._data = datadef __getitem__(self,index):print("in getitem")return self._data[index]def __setitem__(self,index,value):print("in setitem")self._data[index] = valuedef __delitem__(self,index):print("in delitem")del self._data[index]def __repr__(self):return str(self._data)>>> c = cls([11,22,33,44,55])
>>> c[1:3]
in getitem
[22, 33]
>>> c[1:3] = [222,333]
in setitem
>>> c
[11, 222, 333, 44, 55]
>>> del c[1:3]
in delitem

__getitem__索引迭代

__getitem__重载了索引取值和分片操作,实际上它也能重载索引的迭代操作。以for为例,它会循环获取一个个的索引并向后偏移,直到超出索引边界抛出IndexError异常而停止。

此外,__getitem__重载使得它可以被迭代,也就是它通过数值索引的方式让这个对象变成可迭代对象,所有迭代工具(比如zip/map/for/in)都可以对这个对象进行迭代操作。

class cls:def __init__(self,data):self._data = datadef __getitem__(self,index):return self._data[index]def __repr__(self):return str(self._data)>>> c1 = cls([11,22,33,44,55])
>>> I = iter(c1)
>>> next(I)
11
>>> 22 in I
True>>> I=iter(c1)
>>> for i in I:print(i,end=" ")
...
11 22 33 44 55

可迭代对象:__iter____next__

定以了__getitem__的类是可迭代的类型,是通过数值索引的方式进行迭代的,但这是退而求其次的行为,更好的方式是定义__iter__方法,使用迭代协议进行迭代。当同时定义了__iter____getitem__的时候,iter()函数优先选择__iter__,只有在__iter__不存在的时候才会选择__getitem__

例如:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Squares:def __init__(self, start, stop):  # 迭代起始、终止位self.value = startself.stop = stopdef __iter__(self):     # 返回自身的迭代器return selfdef __next__(self):     # 返回下一个元素if self.value > self.stop:   # 结尾时抛出异常raise (StopIteration)item = self.value**2self.value += 1return itemif __name__ == "__main__":for i in Squares(1, 5):print(i, end=" ")s = Squares(1,5)print()print(9 in s)

运行结果:

1 4 9 16 25
True

因为上面的类中同时定义了__iter____next__,且__iter__返回的是自身,所以这个类型的每个迭代对象都是单迭代的。

>>> s = Squares(1,5)
>>> I1 = iter(s)   # I1和I2迭代的是同一个对象
>>> I2 = iter(s)
>>> next(I1)
1
>>> next(I2)   # 继续从前面的位置迭代
4
>>> next(I1)
9

自定义多迭代类型

要定义多迭代的类型,要求__iter__返回一个新的迭代对象,而不是self自身,也就是说不要返回自身的迭代器。

例如:

# 返回多个独立的可迭代对象
class MultiIterator:def __init__(self, wrapped):self.wrapped = wrapped   # 封装将被迭代的对象def __iter__(self):return Next(self.wrapped) # 返回独立的可迭代对象# 自身的迭代器
class Next:def __init__(self, wrapped):self.wrapped = wrappedself.offset = 0def __iter__(self):return selfdef __next__(self):   # 返回下一个元素if self.offset >= len(self.wrapped):raise (StopIteration)else:item = self.wrapped[self.offset]self.offset += 1return item    # 返回指定索引位置处的元素if __name__ == "__main__":string = "abc"s = MultiIterator(string)for x in s:for y in s:print(x + y, end=" ")

每个for迭代工具都会先调用iter()来获取可迭代对象,然后调用next()获取下一个元素。而这里的iter()会调用MultiIterator的__iter__来获取可迭代对象,而MultiIterator所返回的可迭代对象是相互独立的Next对象,因此for x in x和for y in s所迭代的是不同迭代对象,它们都有记录着自己的迭代位置信息。

Python基础教程:自定义迭代器相关推荐

  1. Python基础教程:迭代器

    迭代是什么 迭代指的是一个重复的过程,每次重复都必须基于上一次的结果而继续,单纯的重复并不是迭代,如Python中的for循环就是一个非常好的迭代例子. for item in range(10):p ...

  2. Python基础教程:自定义函数

    函数的形式: def name(param1, param2, ..., paramN):statementsreturn/yield value # optional 和其他需要编译的语言(比如 C ...

  3. python基础教程pdf百度云-《Python基础教程(第3版)》PDF高清版

    <python基础教程第3版>PDF高清版  百度云资源,内涵教材源代码 百度云链接:百度云盘 提取码:7r7o 编辑推荐 久负盛名的Python入门经典,是非常优秀的基础教程,深入浅出, ...

  4. python基础教程电子版-Python基础教程(第2版 修订版) pdf

    Python基础教程(第2版 修订版) 目录 D11章快速改造:基础知识1 1.1安装Python1 1.1.1Windows1 1.1.2Linux和UNIX3 1.1.3苹果机(Macintosh ...

  5. python基础教程-《Python基础教程(第3版)》PDF高清版

    <python基础教程第3版>PDF高清版  百度云资源,内涵教材源代码 百度云链接:百度云盘 提取码:7r7o 编辑推荐 久负盛名的Python入门经典,是非常优秀的基础教程,深入浅出, ...

  6. python基本代码教程-Python基础教程(第3版)

    Python基础教程(第3版) 第2版前言 第1版前言 引言 1 快速上手:基础知识 1.1 交互式解释器 1.2 算法是什么 1.3 数和表达式 十六进制.八进制和二进制 1.4 变量 1.5 语句 ...

  7. python基础教程免费下载-Python基础教程(第2版)

    <Python基础教程(第2版)>内容涉及的范围较广,既能为初学者夯实基础,又能帮助程序员提升技能,适合各个层次的Python开发人员阅读参考.<Python基础教程(第2版)> ...

  8. python黑马教程ppt_,python基础教程 PPT

    python基础教程 PPT Python我这里有Python编开发,进阶,化,实战等系列视频教程,还有安装包,素材,代码内容,这里就不一一说了,全套内容一共300G左右,非常的详细,需要的请到网盘下 ...

  9. 视频教程-快速入门Python基础教程_Python基础知识大全-Python

    快速入门Python基础教程_Python基础知识大全 十余年计算机技术领域从业经验,在中国电信.盛大游戏等多家五百强企业任职技术开发指导顾问,国内IT技术发展奠基人之一. 杨千锋 ¥99.00 立即 ...

  10. python基础教程免费下载-Python基础教程第三版PDF电子书免费下载

    <Python基础教程(第3版)>是2018年人民邮电出版社出版的图书,作者是[挪]Magnus Lie Hetland.该书全面介绍了Python的基础知识和基本概念,包括列表.元组.字 ...

最新文章

  1. SQL Server 储存过程的output 参数
  2. Git从入门到放不下
  3. 正则表达式匹配单个字符(.、[]、\d、\D、\s、\S、\w、\W)
  4. C#接收串口RS232的CD、CTS、DSR信号
  5. Linux内核移植之二:Kconfig分析
  6. 计算机vb输入框函数,VB数据输入函数inputbox
  7. python爬虫实战:利用scrapy,短短50行代码下载整站短视频
  8. window,windowManager --《android 艺术探索读书》笔记
  9. Vue监控器watch的全面解析
  10. 饥荒机器人怎么用避雷针充电_新款iPhone充电线怎么这么好看~安卓也可以用!...
  11. 不安装游戏apk直接启动法
  12. 微信公众号 分享接口 签名通过 分享无效果(JSSDK自定义分享接口的策略调整)...
  13. python独一无二的路_独一无二的Python基础学习——可用作面试
  14. Python列表推导式求素数
  15. 牛客刷题<17>用3-8译码器实现全减器
  16. 用excel制作项目管理甘特图
  17. 决策树--CART算法
  18. 高并发的核心技术-幂等的实现方案
  19. 非诚勿扰24灯全灭php,收二手货小伙上非诚勿扰,24盏灯全灭还遭羞辱,最后才知道是收二手豪车身价上亿...
  20. UIQ全方位实现与ActiveSync进行数据交换(转)

热门文章

  1. 【Spark篇】---Spark中Master-HA和historyServer的搭建和应用
  2. Java泛型详解,通俗易懂
  3. 2016年ICT产业趋势预测
  4. 新手!SDK Manager里找不到API安装的选项怎么办?
  5. JS原生---鼠标拖拽
  6. request.getServletContext()
  7. SSH框架--Struts的故事
  8. Spring BeanFactory实例化Bean的过程
  9. k8s查看pod的yaml文件_【大强哥-k8s从入门到放弃04】Yaml语法解析
  10. 【经济法常识转摘】借款人逾期不还钱,利率如何确定?