python生成器

迭代器是一个对象,而生成器是一个函数,迭代器和生成器是python中两个非常强大的特性,编写程序时你可以不使用生成器达到同样的效果,但是生成器让你的程序更加pythonic。创建生成器非常简单,只要在函数中加入yield语句即可。函数中每次使用yield产生一个值,函数就返回该值,然后停止执行,等待被激活,被激活后继续在原来的位置执行。下边的例子实现了同样的功能:

 1 #!/usr/bin/env python  
 2 #coding=utf-8  
 3 def fib():  
 4     a,b = 0,1  
 5     while 1:  
 6         a,b = b,a+b  
 7         yield a  
 8 for f in fib():  
 9     if f < 10000:  
10         print (f) 
11     else:  
12         break  
13 
14 
15 1
16 1
17 2
18 3
19 5
20 8
21 13
22 21
23 34
24 55
25 89

如何迭代?

    根本上说, 迭代器就是有一个 next() 方法的对象, 而不是通过索引来计数. 当你或是一个循环机制(例如 for 语句)需要下一个项时, 调用迭代器的 next() 方法就可以获得它. 条目全部取出后, 会引发一个 StopIteration 异常, 这并不表示错误发生, 只是告诉外部调用者, 迭代完成.

    不过, 迭代器也有一些限制. 例如你不能向后移动, 不能回到开始, 也不能复制一个迭代器.如果你要再次(或者是同时)迭代同个对象, 你只能去创建另一个迭代器对象. 不过, 这并不糟糕,因为还有其他的工具来帮助你使用迭代器. 

    reversed() 内建函数将返回一个反序访问的迭代器. enumerate() 内建函数同样也返回迭代器.另外两个新的内建函数, any() 和 all() , 在 Python 2.5 中新增, 如果迭代器中某个/所有条目的值都为布尔真时,则它们返回值为真. 本章先前部分我们展示了如何在 for 循环中通过索引或是可迭代对象来遍历条目. 同时 Python 还提供了一整个 itertools 模块, 它包含各种有用的迭代器.

迭代器工作原理
   如果这是一个实际应用程序, 那么我们需要把代码放在一个 try-except 块中. 序列现在会自 
动地产生它们自己的迭代器, 所以一个 for 循环: 

for i in seq:  
    do_something_to(i)

实际上是这样工作的:

fetch =  seq.__iter__
#iter(seq)
while True:
    try:
        i = fetch.next()
    except StopIteration:
        break
do_something_to(i)

另外, 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() :

>>>myFile=open(‘config-win.txt’)  
  
>>> for eachLine in myFile:  
… print eachLine, # comma suppresses extra n  
…  
[EditorWindow]  
font-name: courier new  
font-size: 10  
>>> myFile.close()  

可变对象和迭代器

    记住,在迭代可变对象的时候修改它们并不是个好主意. 这在迭代器出现之前就是一个问题.
一个流行的例子就是循环列表的时候删除满足(或不满足)特定条件的项:

for eachURL in allURLs:  
    if not eachURL.startswith(‘http://’):  
        allURLs.remove(eachURL) # YIKES!! 

除列表外的其他序列都是不可变的, 所以危险就发生在这里. 一个序列的迭代器只是记录你当前到达第多少个元素, 所以如果你在迭代时改变了元素, 更新会立即反映到你所迭代的条目上.在迭代字典的 key 时, 你绝对不能改变这个字典. 使用字典的 keys() 方法是可以的, 因为keys() 返回一个独立于字典的列表. 而迭代器是与实际对象绑定在一起的, 它将不会继续执行下去:

myDict = {'a': 1, 'b': 2, 'b': 3, 'd': 4}  
for eachKey in myDict:
    print (eachKey, myDict[eachKey])
    del myDict[eachKey] 

'''
结果:
d 4
Traceback (most recent call last):
  File "test.py", line 2, in <module>
    for eachKey in myDict:
RuntimeError: dictionary changed size during iteration
'''

这样可以避免有缺陷的代码. 更多有关迭代器的细节请参阅 PEP 234 .

如何创建迭代器

对一个对象调用 iter() 就可以得到它的迭代器. 它的语法如下:

iter(obj)  
iter(func, sentinel)  

如果你传递一个参数给 iter() , 它会检查你传递的是不是一个序列, 如果是, 那么很简单: 
根据索引从 0 一直迭代到序列结束. 另一个创建迭代器的方法是使用类, 我们将在第 13 章详细 
介绍, 一个实现了 __iter__() 和 next() 方法的类可以作为迭代器使用.

如果是传递两个参数给 iter() , 它会重复地调用 func , 直到迭代器的下个值等于sentinel .

公众号请关注:侠之大者
原文地址:https://www.cnblogs.com/kamil/p/5207258.html