一个不错的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的封装更加易懂和易用。
Posted on 2015-05-08 16:31  bob.dong  阅读(50)  评论(0编辑  收藏  举报