您的位置:首页 > 编程语言 > Python开发

python生成器

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

#!/usr/bin/env python
#coding=utf-8
def fib():
a,b = 0,1
while 1:
a,b = b,a+b
yield a
for f in fib():
if f < 10000:
print (f)
else:
break

1
1
2
3
5
8
13
21
34
55
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 .
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: