网站收录了文章不收录,wordpress视频教学,晋江交流区,平面设计公司电话1. 迭代器 迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问#xff0c;知道所有的元素被访问完结束。迭代器只能往前不会后退#xff0c;不过这也没什么#xff0c;因为人们很少在迭代途中往后退。 1.1 使用迭代器的优点 对于原生支持随机访问的数据…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() 执行 1 2 3 4 5 6 7 8 9 for key in Fabs(5): print key 1 1 2 3 5 Fabs 类通过 next() 不断返回数列的下一个数内存占用始终为常数 1.2 使用迭代器 使用内建的工厂函数iter(iterable)可以获取迭代器对象 1 2 3 4 lst range(5) it iter(lst) it listiterator object at 0x01A63110 使用next()方法可以访问下一个元素 1 2 3 4 5 6 it.next() 0 it.next() 1 it.next() 2 python处理迭代器越界是抛出StopIteration异常 1 2 3 4 5 6 7 8 9 10 11 12 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 结果 1 2 3 4 5 6 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 结果 1 2 3 4 5 6 __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 执行 1 2 3 4 5 6 7 8 9 for n in fab(5): print n 1 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 的执行流程 1 2 3 4 5 6 7 8 9 10 11 12 13 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 终止迭代。例如 1 2 3 4 5 6 7 8 9 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.列表生成式→生成器 只要把一个列表生成式的[]改成()就创建了一个generator 1 #列表生成式
2 li[x*x for x in range(10) if x%20] #占用内存
3
4
5 #生成器
6 g(x*x for x in range(10) if x%20)
7 #用for来循环访问不用考虑异常溢出问题
8 for i in g:
9 print(i) View Code 4.迭代器读取文件 使用迭代器一个显而易见的好处就是每次只从对象中读取一条数据不会造成内存的过大开销。 比如要逐行读取一个文件的内容利用readlines()方法我们可以这么写 12 for line in open(test.txt).readlines(): print line 这样虽然可以工作但不是最好的方法。因为他实际上是把文件一次加载到内存中然后逐行打印。当文件很大时这个方法的内存开销就很大了。 利用file的迭代器我们可以这样写 12 for line in open(test.txt): #use file iterators print line 这是最简单也是运行速度最快的写法他并没显式的读取文件而是利用迭代器每次读取下一行。 转载于:https://www.cnblogs.com/yizhenfeng168/p/6916729.html