一个不错的generator的例子 听说Python也有类似C++ STL的iterator,今天看了看,Python的东西真是好懂啊,几分钟就看完了iterator和genrator的Tutorial。Tutorial一开始先提醒我们for语句是很强大滴,只要是个容器(container),用for就可以遍历里面所有元素。例如:
for element in [1, 2, 3]:
print element
for element in (1, 2, 3):
print element
for key in {'one':1, 'two':2}:
print key
for char in "123":
print char
for line in open("myfile.txt"):
print line
然后Tutorial中接着解释,其实for是使用了in后面那个对象的iterator。每次调用iterator的next方法都可以得到下一个元素。到了最后一个元素时系统会抛出一个称为StopIteration的Exception,使for语句终止。只要为自己写的类加上__iter__()方法和next()方法,也能够使用for语句来遍历所有元素。具体细节就不讲了,因为这只是引出generator的一个过渡。
为了使iterator更直观、生成更简单,Python引入了generator。generator对象可以起到类似container的作用,container中的元素内容由generator中的语句确定。例如:
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
>>> for char in reverse('golf'):
... print char
...
f
l
o
g
在实现上,generator并不是生成一个列表,然后再由for对元素一个一个进行处理,而是一次只返回一个元素(用yield语句)并保存generator的状态,等下次被调用时再从当前状态往下执行,这样可以省却保存整个大列表的存储代价。
为了练手,我写了两个等价的程序,它们可以列出某个目录下能找到的所有文件名:
(1)不用generator:
import os
def PrintName(fn):
print 'Found new file:' + fn
def ForEachFile(root, func):
for dir_entry in os.walk(root): # 对找到的每个目录,os.walk()返回[目录名,子目录列表,文件名列表] (其实os.walk本身就是个generator)
for fName in dir_entry[2]:
fFullName = dir_entry[0]+'\'+fName
func(fFullName)
ForEachFile('d:\temp', PrintName)
(2)使用generator:
import os
def RecursiveFileList(root):
for dir_entry in os.walk(root):
for fName in dir_entry[2]:
yield dir_entry[0] + '\' + fName
for fn in RecursiveFileList('d:\temp'):
print 'Found new file: ', fn
对比之下,用了generator的封装更加易懂和易用。
原文地址:Python的Iterator和Generator作者:珍惜眼前