1. 迭代器

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。

1.1 使用迭代器的优点

对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。

另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。

迭代器更大的功劳是提供了一个统一的访问集合的接口,只要定义了__iter__()方法对象,就可以使用迭代器访问。

迭代器有两个基本的方法

  • next方法:返回迭代器的下一个元素
  • __iter__方法:返回迭代器对象本身

下面用生成斐波那契数列为例子,说明为何用迭代器

代码1

 def fab(max): n, a, b = 0, 0, 1 while n < max: print b a, b = b, a + b n = n + 1

直接在函数fab(max)中用print打印会导致函数的可复用性变差,因为fab返回None。其他函数无法获得fab函数返回的数列。

代码2

 def fab(max): L = []n, a, b = 0, 0, 1 while n < max: L.append(b) a, b = b, a + b n = n + 1return L

代码2满足了可复用性的需求,但是占用了内存空间,最好不要。

代码3

对比

 for i in range(1000): pass

 for i in xrange(1000): pass

前一个返回1000个元素的列表,而后一个在每次迭代中返回一个元素,因此可以使用迭代器来解决复用可占空间的问题

 class Fab(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration()

执行

>>> for key in Fabs(5):print key1
1
2
3
5

Fabs 类通过 next() 不断返回数列的下一个数,内存占用始终为常数  

1.2 使用迭代器

使用内建的工厂函数iter(iterable)可以获取迭代器对象:

>>> lst = range(5)
>>> it = iter(lst)
>>> it
<listiterator object at 0x01A63110>

使用next()方法可以访问下一个元素:

>>> it.next()
0
>>> it.next()
1
>>> it.next()
2

python处理迭代器越界是抛出StopIteration异常

>>> it.next()
3
>>> it.next
<method-wrapper 'next' of listiterator object at 0x01A63110>
>>> it.next()
4
>>> it.next()Traceback (most recent call last):File "<pyshell#27>", line 1, in <module>it.next()
StopIteration

了解了StopIteration,可以使用迭代器进行遍历了

lst = range(5)
it = iter(lst)
try:while True:val = it.next()print val
except StopIteration:pass

结果

>>>
0
1
2
3
4

事实上,因为迭代器如此普遍,python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。如下

>>> a = (1, 2, 3, 4)
>>> for key in a:print key1
2
3
4

首先python对关键字in后的对象调用iter函数迭代器,然后调用迭代器的next方法获得元素,直到抛出StopIteration异常。

1.3 定义迭代器

下面一个例子——斐波那契数列

# -*- coding: cp936 -*-
class Fabs(object):def __init__(self,max):self.max = maxself.n, self.a, self.b = 0, 0, 1  #特别指出:第0项是0,第1项是第一个1.整个数列从1开始def __iter__(self):return selfdef next(self):if self.n < self.max:r = self.bself.a, self.b = self.b, self.a + self.bself.n = self.n + 1return rraise StopIteration()print Fabs(5)
for key in Fabs(5):print key

结果

<__main__.Fabs object at 0x01A63090>
1
1
2
3
5

2. 生成器

带有 yield 的函数在 Python 中被称之为 generator(生成器),几个例子说明下(还是用生成斐波那契数列说明)

可以看出代码3远没有代码1简洁,生成器(yield)既可以保持代码1的简洁性,又可以保持代码3的效果

代码4 

def fab(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1

执行

>>> for n in fab(5):print n1
1
2
3
5

简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程:

>>> f = fab(3)
>>> f.next()
1
>>> f.next()
1
>>> f.next()
2
>>> f.next()Traceback (most recent call last):File "<pyshell#62>", line 1, in <module>f.next()
StopIteration

return作用

在一个生成器中,如果没有return,则默认执行到函数完毕;如果遇到return,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。例如

>>> s = fab(5)
>>> s.next()
1
>>> s.next()Traceback (most recent call last):File "<pyshell#66>", line 1, in <module>s.next()
StopIteration

代码5  文件读取

 def read_file(fpath): BLOCK_SIZE = 1024 with open(fpath, 'rb') as f: while True: block = f.read(BLOCK_SIZE) if block: yield block else: return

如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取。

3. 参考

Python函数式编程指南(三):迭代器

Python yield 使用浅析

python 迭代器 生成器相关推荐

  1. python迭代器生成器 学会再缩短一半开发效率 看看大牛是怎么写的

    一.迭代 什么叫做迭代? 比如在 Java 中,我们通过 List 集合的下标来遍历 List 集合中的元素,在 Python 中,给定一个 list 或 tuple,我们可以通过 for 循环来遍历 ...

  2. python 迭代器 生成器_Python迭代器和生成器

    迭代器认知 迭代器 (iterator): 如果一个对象同时有__iter__()和__next__()魔术方法的话,这个对象就可以称为是迭代器. __iter__()的作用是可以让for循环遍历.而 ...

  3. python迭代器生成器装饰器

    基本概念 学习python中有什么不懂的地方,小编这里推荐加小编的python学习群:895 817 687有任何不懂的都可以在里面交流,还有很好的视频教程pdf学习资料,大家一起学习交流! 1.容器 ...

  4. python 生成器装饰器_4.python迭代器生成器装饰器

    基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...

  5. python 迭代器 生成器_python 迭代器与生成器

    迭代器 迭代器就是iter(可迭代对象函数)返回的对象,说人话.......可迭代对象由一个个迭代器组成 可以用next()函数获取可迭代对象的数据 迭代是访问集合元素的一种方式(因为集合是无序的,所 ...

  6. python 生成器装饰器_七.python迭代器生成器装饰器

    1.迭代器 1.1 什么是可迭代对象(Iterable)? 定义:可以直接作用于for循环的对象统称为可迭代对象,即Iterable. 可迭代对象包括: 1.集合数据类型:如list.tuple.di ...

  7. python迭代器生成器使用技巧(2):切片、遍历、索引值、多序列、多容器对象

    1. 迭代器切片 迭代器和生成器不能使用标准的切片操作,因为它们的长度事先并不知道(并且也没有实现索引). 函数 islice() 返回一个可以生成指定元素的迭代器,通过遍历并丢弃直到切片开始索引位置 ...

  8. python迭代器生成器使用技巧(1):遍历、代理、生成器创建迭代、反向迭代

    1. 手动遍历迭代器 next() 遍历一个可迭代对象中的所有元素,但是却不想使用for循环.为了手动的遍历可迭代对象,使用 next() 函数并在代码中捕获 StopIteration 异常. 通常 ...

  9. python 迭代器生成器

    目录 一.可迭代对象 1.1 判断是否为可迭代对象 二.迭代器 2.1 判断对象是否是一个迭代器 2.2 手写一个迭代器 2.3 迭代器应用场景 三.生成器 3.1 生成器介绍 3.2 使用yield ...

最新文章

  1. 浏览器兼容:IE6,IE7,IE8,FIREFOX,Chrome
  2. 如何利用遗传算法进行自变量降维(代码部分)
  3. 如何通过机器学习还原图像色彩
  4. 许可证无效_未取得预售许可证所签买房合同是否一概无效?
  5. ant 构建_有用的Ant构建标签
  6. php验证支付回调,php对微信支付回调处理的方法(合集)
  7. 深度学习自学(十七):caffe-sphereface-编译matcaffe遇到的问题
  8. apk html启动图,apk添加启动图(AddApkSplashTools)
  9. 51单片机学习 光敏电阻传感器实验
  10. Linux中arp表的老化机制
  11. 阿里云 DataV 产品简介
  12. [渝粤教育] 西南科技大学 英语(B)1 在线考试复习资料
  13. 【FLUENT】【VOF】液滴铺展问题模拟示例
  14. 【React】unmountComponentAtNode卸载组件
  15. 用前端代码智能识别身份证的头像
  16. java修改文件一行_java替换文件中某一行文本的内容
  17. React中的浅比较是如何工作的?
  18. 【我们是冠军】2021年大数据领域第一名の博客之星活动复盘
  19. 【前端】JavaScript —— WebAPI
  20. python抖音屏幕滑动_python实现抖音点赞功能

热门文章

  1. JAVA正则提取字符串中的日期
  2. 第2章[2.4] Ext JS的类与类体系
  3. Perl -- 使用Perl 读取和发送邮件
  4. Javascript模块化编程系列二: 模块化的标准化(CommonJS AMD)
  5. TeamCenter开发系统设计系列之一
  6. java语言的技术可行性_可行性分析的主要内容( )。
  7. Linux中设置Docker的yum源时,报-bash: yum-config-manager: command not found错误
  8. 正则提取Swagger在线文档里面的返回实体类字段
  9. 修改字段名和字段备注
  10. 重启物理机后kvm无法启动虚拟机