Python中Iterator迭代器的使用杂谈


Posted in Python onJune 20, 2016

迭代器是一种支持next()操作的对象。它包含一组元素,当执行next()操作时,返回其中一个元素;当所有元素都被返回后,生成一个StopIteration异常。

>>>a=[1,2,3]
>>>ia=iter(a)
>>>next(ia)
1
>>>next(ia)
2
>>>next(ia)
3
>>>next(ia)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

ite()可以接受多种Python对象为参数,比如list,tuple, dict, set等,并将其转化为迭代器。迭代器可以用于for语句或in语句中。很多常用操作也是支持迭代器的,比如sum(), max()等。

>>> b=[4,5,6]
>>> ib=iter(b)
>>> for x in ib:
...   print(x)
...
4
5
6
>>> ic=iter(b)
>>> sum(ic)
15
>>> id=iter(b)
>>> max(ic)
6

毋庸置疑,迭代器有很多好处:

1.“流式”数据处理方式减少内存消耗:
比如处理文件,一下猛地把全部数据全部取出来放到内存里面进行处理会导致程序消耗大量内存,有时甚至没法做到,一般我们会一部分一部分的对文件内容进行处理:

for text_line in open("xx.txt"):
 print text_line

2.或者对xml文件进行处理的时候:

tree = etree.iterparse(xml, ['start', 'end'])
for event, elem in tree:
  if event == "end"
    result = etree.tostring(elem)
    elem.clear()
    print result

内置函数open返回的file对象和etree.iterparse序列化的xml tree都是可迭代对象,能够让我们渐进式地对文件的内容进行处理。

3.支持方便用for语句对数据进行消费:
python内置的一些常见的像类型像数组、列表甚至字符串等都是可迭代类型,这样我们就能方便for语句这个语法糖方便对数据进行消费,不需要自己记录索引位置,人肉循环:

for i in [1, 2, 3, 4]
 print i,

简单了解了一下迭代器的好处后,我们正正经经的聊聊python的迭代器模式。
在这里我们引入两个比较绕口的名词:可迭代对象和迭代器对象,个人觉得从这两个概念下手会对迭代器有比较好的理解。在放例子前先对这两个概念给一个不入流的解释:

可迭代对象:对象里面包含__iter()__方法的实现,对象的iter函数经调用之后会返回一个迭代器,里面包含具体数据获取的实现。
迭代器:包含有next方法的实现,在正确范围内返回期待的数据以及超出范围后能够抛出StopIteration的错误停止迭代。
放个例子边看边说:

class iterable_range:
  def __init__(self, n):
    self.n = n

  def __iter__(self):
    return my_range_iterator(self.n)

class my_range_iterator:
  def __init__(self, n):
    self.i = 0
    self.n = n

  def next(self):
    if self.i < self.n:
      i = self.i
      self.i += 1
      print 'iterator get number:', i
      return i
    else:
      raise StopIteration()

例子中的iterable_range是一个可迭代对象,所以我们也能够对它用for语句来进行迭代:

temp = my_range(10)
for item in temp:
  print item,

输出:

my iterator get number: 0
  0
  my iterator get number: 1
  1
  my iterator get number: 2
  2
  my iterator get number: 3
  3
  my iterator get number: 4
  4
  my iterator get number: 5
  5
  my iterator get number: 6
  6
  my iterator get number: 7
  7
  my iterator get number: 8
  8
  my iterator get number: 9
  9

大家可以仔细地看一下输出的日志:

  • 数据确实是“流式”处理的
  • iterator是真正在背后做事的人
  • for语句能够非常方便的迭代对象的数据。

可迭代对象其实更像是整个迭代器模式模式的上层,像一种约束一种契约一种规范,它能够保证自己能够返回一个在实际工作中干活的迭代器对象。for、sum等接受一个可迭代对象的方法都是遵循这样的规范:调用对象的__iter__函数,返回迭代器,对迭代器对象返回的每个值进行处理抑或需要一些汇总的操作。拿for举个例子:

iterator_object = iterable_object.__iter__()
while True:
  try:
    value = iterator_object.next()
  except StopIteration:
    # StopIteration exception is raised after last element
    break

  # loop code
  print value

for这个语法糖背后的逻辑差不多就是上面例子中代码所示的那样:首先获取可迭代对象返回的迭代器对象,然后调用迭代器对象的next方法获取每个值,在获取值的过程中随时检测边界-也就是检查是否抛出了StopIteration这样的错误,如果迭代器对象抛出错误则迭代停止(note:从这个例子可以看出,对于那些接受可迭代对象的方法,如果我们传一个单纯的迭代器对象其实也是无法工作的,可能会报出类似于TypeError: iteration over non-sequence的错误)。
当然了,一般在应用过程中我们不会将他们特意的分开,我们能够稍微对迭代器对象进行修改一下,添加__iter__方法的实现,这样对象本身就既是可迭代对象也是一个迭代器对象了:

class my_range_iterator:
   def __init__(self, n):
    self.i = 0
    self.n = n

   def __iter__(self):
    return self

   def next(self):
    if self.i < self.n:
      i = self.i

      self.i += 1
      print 'my iterator get number:', i
      return i
    else:
      raise StopIteration()

 for item in my_range_iterator(10):
   print item

输出:

 

my iterator get number: 0
  0
  my iterator get number: 1
  1
  my iterator get number: 2
  2
  my iterator get number: 3
  3
  my iterator get number: 4
  4
  my iterator get number: 5
  5
  my iterator get number: 6
  6
  my iterator get number: 7
  7
  my iterator get number: 8
  8
  my iterator get number: 9
  9
Python 相关文章推荐
Python pickle模块用法实例
Apr 14 Python
Python中的pass语句使用方法讲解
May 14 Python
详解Django中的form库的使用
Jul 18 Python
编写自定义的Django模板加载器的简单示例
Jul 21 Python
python在ubuntu中的几种安装方法(小结)
Dec 08 Python
浅谈Python中的zip()与*zip()函数详解
Feb 24 Python
Python根据已知邻接矩阵绘制无向图操作示例
Jun 23 Python
详解python做UI界面的方法
Feb 27 Python
python使用 zip 同时迭代多个序列示例
Jul 06 Python
Python log模块logging记录打印用法解析
Jan 20 Python
基于Python的身份证验证识别和数据处理详解
Nov 14 Python
pycharm中选中一个单词替换所有重复单词的实现方法
Nov 17 Python
实例讲解Python编程中@property装饰器的用法
Jun 20 #Python
Python的包管理器pip更换软件源的方法详解
Jun 20 #Python
python3.5使用tkinter制作记事本
Jun 20 #Python
浅谈python抛出异常、自定义异常, 传递异常
Jun 20 #Python
python3 与python2 异常处理的区别与联系
Jun 19 #Python
浅谈Python的异常处理
Jun 19 #Python
qpython3 读取安卓lastpass Cookies
Jun 19 #Python
You might like
用PHP和ACCESS写聊天室(十)
2006/10/09 PHP
几种有用的变型 PHP中循环语句的用法介绍
2012/01/30 PHP
php生成excel列序号代码实例
2013/12/24 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
PHP+mysql实现的三级联动菜单功能示例
2019/02/15 PHP
新发现一个骗链接的方法(js读取cookies)
2012/01/11 Javascript
文本域光标操作的jQuery扩展分享
2014/03/10 Javascript
JavaScript截取字符串的Slice、Substring、Substr函数详解和比较
2014/03/20 Javascript
js创建对象的区别示例介绍
2014/07/24 Javascript
再谈javascript原型继承
2014/11/10 Javascript
jquery实现炫酷的叠加层自动切换特效
2015/02/01 Javascript
JavaScript获取元素尺寸和大小操作总结
2015/02/27 Javascript
javascript中数组方法汇总
2015/07/07 Javascript
node.js连接mongoDB数据库 快速搭建自己的web服务
2016/04/17 Javascript
输入法的回车与消息发送快捷键回车的冲突解决方法
2016/08/09 Javascript
AngularJS解决ng界面长表达式(ui-set)的方法分析
2016/11/07 Javascript
javascript中setAttribute兼容性用法分析
2016/12/12 Javascript
js+html5实现复制文字按钮
2017/07/15 Javascript
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
2019/03/01 Javascript
微信小程序学习笔记之登录API与获取用户信息操作图文详解
2019/03/29 Javascript
Vue管理系统前端之组件拆分封装详解
2020/08/23 Javascript
JavaScript中CreateTextFile函数
2020/08/30 Javascript
从运行效率与开发效率比较Python和C++
2018/12/14 Python
Python两个字典键同值相加的几种方法
2019/03/05 Python
一篇文章彻底搞懂Python中可迭代(Iterable)、迭代器(Iterator)与生成器(Generator)的概念
2019/05/13 Python
Python3.x+迅雷x 自动下载高分电影的实现方法
2020/01/12 Python
pyinstaller打包成无控制台程序时运行出错(与popen冲突的解决方法)
2020/04/15 Python
MoviePy常用剪辑类及Python视频剪辑自动化
2020/12/18 Python
C#里面如何倒序排列一个数组的元素?
2013/06/21 面试题
大型车展策划方案
2014/02/01 职场文书
公共场所标语
2014/06/30 职场文书
公司副总经理岗位职责
2014/10/01 职场文书
廉政承诺书
2015/01/19 职场文书
民事起诉状范文
2015/05/19 职场文书
2019朋友新婚祝福语精选
2019/10/10 职场文书
Mysql数据库按时间点恢复实战记录
2021/06/30 MySQL