Python迭代和解析(4):自定义迭代器

发布时间:2019-01-13 17:10,

浏览次数:280

, 标签:

Python

解析、迭代和生成系列文章:https://www.cnblogs.com/f-ck-need-u/p/9832640.html

本文介绍如何自定义迭代器,涉及到类的运算符重载,包括__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__方法,它们会重载索引取值:

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 = data def

__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__()方法。

class cls: def __init__(self,data): self._data = data def

__getitem__(self,index): print("in getitem") return self._data[index] def

__setitem__(self,index,value): print("in setitem") self._data[index] = value

def __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 = data def

__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__。

例如:

class Squares: def __init__(self, start, stop): # 迭代起始、终止位 self.value = start

self.stop = stop def __iter__(self): # 返回自身的迭代器 return self def __next__(self):

# 返回下一个元素 if self.value > self.stop: # 结尾时抛出异常 raise (StopIteration) item =

self.value**2 self.value += 1 return item if __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 =

wrapped self.offset = 0 def __iter__(self): return self def __next__(self): #

返回下一个元素 if self.offset >= len(self.wrapped): raise (StopIteration) else: item =

self.wrapped[self.offset] self.offset += 1 return 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 跳过迭代_Python迭代和解析(4):自定义迭代器相关推荐

  1. python迭代_Python迭代

    >>> f = open("208.txt") >>> f.readline() #读第一行 'Learn python with qiwsir ...

  2. python 跳一跳辅助_python实现跳一跳辅助的实验报告

    微信跳一跳(python实现) >>>本文记录小编尝试用python玩微信跳一跳的实验过程. 正所谓巨人的肩膀是一个很nice的地方,早有大神编辑出了实现该操作的方法.就是这位: p ...

  3. python 命令行解析函数_python命令行解析之parse_known_args()函数和parse_args()使用区别介绍...

    在python中,命令行解析的很好用, 首先导入命令行解析模块 import argparse import sys 然后创建对象 parse=argparse.ArgumentParser() 然后 ...

  4. python爬取网页内容_Python爬虫原理解析

    笔者公众号:技术杂学铺 笔者网站:mwhitelab.com 本文将从何为爬虫.网页结构.python代码实现等方面逐步解析网络爬虫. 1. 何为爬虫 如今互联网上存储着大量的信息. 作为普通网民,我 ...

  5. python处理pdf实例_python使用pdfminer解析pdf文件的方法示例

    最近要做个从 pdf 文件中抽取文本内容的工具,大概查了一下 python 里可以使用 pdfminer 来实现.下面就看看怎样使用吧. PDFMiner是一个可以从PDF文档中提取信息的工具.与其他 ...

  6. python zxing 识别条码_Python zxing 库解析(条形码二维码识别)

    各种扫码软件 最近要做个二维码识别的项目,查到二维码识别有好多开源的不开源的软件 Zbar 首先试了一下Zbar,python加载ZBar时各种报错.可能的原因是zbar的dll文件是32位的,而我系 ...

  7. python中的参数_python中参数解析

    取得命令行参数 在使用之前,首先要取得命令行参数.使用sys模块可以得到命令行参数. import sys print sys.argv 然后在命令行下敲入任意的参数,如: python get.py ...

  8. python切片步长为负数_Python切片知识解析

    切片原型 strs = 'abcdefg' Strs[start: end:step] 切片的三个参数分别表开始,结束,步长 第一位下标为0,end位不取,如strs[1:3] = 'bc' 如果st ...

  9. python制作动态时钟_python+pygame制作一个可自定义的动态时钟和详解

    #第1步:导出模块 importsys, random, math, pygamefrom pygame.locals import * from datetime importdatetime, d ...

最新文章

  1. numpy库中ones和zeros函数传入的shape(表示各个维度的度数)参数的详解
  2. Linux常用测试命令
  3. 【BZOJ】3390: [Usaco2004 Dec]Bad Cowtractors牛的报复(kruskal)
  4. android shape 自定义,Android自定义shape的使用
  5. Maven入门详解与安装配置
  6. DNS域名解析中添加的各项记录详解
  7. Guava 之 Splitter
  8. 【矩阵论】线性空间与线性变换(2)
  9. 全部口罩机3D图纸图档打包
  10. 基于AI的计算机视觉识别在Java项目中的使用(三) —— 搭建基于Docker的深度学习训练环境
  11. 我偷看了老板的微信分组,整个人都不好了…
  12. 你的华为手机还会卡?那是这3个功能没设置吧,越早关掉越好
  13. 解决Chrome自带翻译功能无法使用问题
  14. 基于weixin-java-tools集成微信小程序支付功能
  15. 《无懈可击的Web设计》_灵活的文字
  16. 红帽linux6主板,Linux_I810 Graphics LINUX Driver的安装,我的机子的主板是承启6WIV主板 - phpStudy...
  17. 在windows下制作mac os x的启动安装U盘
  18. 小软件神器集合(不定期更新)
  19. MySQL数据库安全策略
  20. 和信锐智陶建辉:金融危机降低人才使用成本

热门文章

  1. python 零基础学习之路-01 计算机硬件
  2. vuejs,angularjs,reactjs介绍
  3. 01Python基础_09异常
  4. Ajax操作的四个步骤
  5. PHP计划任务:如何使用Linux的Crontab执行PHP脚本
  6. AutoHotKey Script AHK脚本++Topre Realforce 104Pro十周年纪念版静电容键盘
  7. Inside Linux kernel
  8. WCF RIA 服务 (三十二)-- 身份验证、角色、个性化 3
  9. HRegionServer异常下线问题
  10. oracle所有的乱码解决方案