转载自 http://blog.csdn.net/bluebird_237/article/details/38894617python
迭代器就是重复地作一些事情,能够简单的理解为循环,在python中实现了__iter__方法的对象是可迭代的,实现了next()方法的对象是迭代器,这样提及来有点拗口,实际上要想让一个迭代器工做,至少要实现__iter__方法和next方法。不少时候使用迭代器完成的工做使用列表也能够完成,可是若是有不少值列表就会占用太多的内存,并且使用迭代器也让咱们的程序更加通用、优雅、pythonic。程序员
若是一个类想被用于for ... in
循环,相似list或tuple那样,就必须实现一个__iter__()
方法,该方法返回一个迭代对象,而后,Python的for循环就会不断调用该迭代对象的next()
方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。函数
咱们以斐波那契数列为例,写一个Fib类,能够做用于for循环:工具
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例自己就是迭代对象,故返回本身 def next(self): self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration(); return self.a # 返回下一个值
如今,试试把Fib实例做用于for循环:fetch
>>> for n in Fib(): ... print n ... 1 1 2 3 5 ... 46368 75025
迭代器是一个对象,而生成器是一个函数,迭代器和生成器是python中两个很是强大的特性,编写程序时你能够不使用生成器达到一样的效果,可是生成器让你的程序更加pythonic。建立生成器很是简单,只要在函数中加入yield语句便可。函数中每次使用yield产生一个值,函数就返回该值,而后中止执行,等待被激活,被激活后继续在原来的位置执行。下边的例子实现了一样的功能:spa
根本上说, 迭代器就是有一个 next() 方法的对象, 而不是经过索引来计数. 当你或是一个循环机制(例如 for 语句)须要下一个项时, 调用迭代器的 next() 方法就能够得到它. 条目所有取出后, 会引起一个 StopIteration 异常, 这并不表示错误发生, 只是告诉外部调用者, 迭代完成..net
不过, 迭代器也有一些限制. 例如你不能向后移动, 不能回到开始, 也不能复制一个迭代器.若是你要再次(或者是同时)迭代同个对象, 你只能去建立另外一个迭代器对象. 不过, 这并不糟糕,由于还有其余的工具来帮助你使用迭代器. code
reversed() 内建函数将返回一个反序访问的迭代器. enumerate() 内建函数一样也返回迭代器.另外两个新的内建函数, any() 和 all() , 在 Python 2.5 中新增, 若是迭代器中某个/全部条目的值都为布尔真时,则它们返回值为真. 本章先前部分咱们展现了如何在 for 循环中经过索引或是可迭代对象来遍历条目. 同时 Python 还提供了一整个 itertools 模块, 它包含各类有用的迭代器.对象
迭代器工做原理
若是这是一个实际应用程序, 那么咱们须要把代码放在一个 try-except 块中. 序列如今会自
动地产生它们本身的迭代器, 因此一个 for 循环: blog
其实是这样工做的:
另外, Python 还引进了三个新的内建字典方法来定义迭代: myDict.iterkeys() (经过 keys 迭
代), myDict.itervalues() (经过 values 迭代), 以及 myDicit.iteritems() (经过 key/value 对来迭代). 注意, in 操做符也能够用于检查字典的 key 是否存在 , 以前的布尔表达式myDict.has_key(anyKey) 能够被简写为 anyKey in myDict .
===文件===
文件对象生成的迭代器会自动调用 readline() 方法. 这样, 循环就能够访问文本文件的全部
行. 程序员可使用 更简单的 for eachLine in myFile 替换 for eachLine in myFile.readlines() :
记住,在迭代可变对象的时候修改它们并非个好主意. 这在迭代器出现以前就是一个问题.
一个流行的例子就是循环列表的时候删除知足(或不知足)特定条件的项:
除列表外的其余序列都是不可变的, 因此危险就发生在这里. 一个序列的迭代器只是记录你当前到达第多少个元素, 因此若是你在迭代时改变了元素, 更新会当即反映到你所迭代的条目上.在迭代字典的 key 时, 你绝对不能改变这个字典. 使用字典的 keys() 方法是能够的, 由于keys() 返回一个独立于字典的列表. 而迭代器是与实际对象绑定在一块儿的, 它将不会继续执行下去:
这样能够避免有缺陷的代码. 更多有关迭代器的细节请参阅 PEP 234 .
对一个对象调用 iter() 就能够获得它的迭代器. 它的语法以下:
若是你传递一个参数给 iter() , 它会检查你传递的是否是一个序列, 若是是, 那么很简单:
根据索引从 0 一直迭代到序列结束. 另外一个建立迭代器的方法是使用类, 咱们将在第 13 章详细
介绍, 一个实现了 __iter__() 和 next() 方法的类能够做为迭代器使用.
若是是传递两个参数给 iter() , 它会重复地调用 func , 直到迭代器的下个值等于sentinel .