`

从os.walk()来看生成器

阅读更多

在Python中,文件遍历是一件非常轻松简便的工作。官方给出的示例:

import os
    from os.path import join, getsize
    for root, dirs, files in os.walk('python/Lib/email'):
        print root, "consumes",
        print sum([getsize(join(root, name)) for name in files]),
        print "bytes in", len(files), "non-directory files"
        if 'CVS' in dirs:
            dirs.remove('CVS')  # don't visit CVS directories

 可以看到,基本上就是依赖os.walk()这个函数来实现的。从结构上来看,for root, dirs, files in os.walk(...),很容易让人认为os.walk(...)生成了一个迭代器。迭代器的next方法可能会返回下一层次的文件夹内容。事实上,os.walk()是一个生成器函数。生成器与迭代器,是Python引入的几大特性之一,而生成器要比迭代器高级一些。至于生成器的工作原理和适用场合,可以先从os.walk()的源码说起。

 

os.walk()源码:

def walk(top, topdown=True, onerror=None, followlinks=False):
    from os.path import join, isdir, islink

 try:
        # Note that listdir and error are globals in this module due
        # to earlier import-*.
        names = listdir(top)
    except error, err:
        if onerror is not None:
            onerror(err)
        return

    dirs, nondirs = [], []
    for name in names:
        if isdir(join(top, name)):
            dirs.append(name)
        else:
            nondirs.append(name)

    if topdown:
        yield top, dirs, nondirs
    for name in dirs:
        path = join(top, name)
        if followlinks or not islink(path):
            for x in walk(path, topdown, onerror, followlinks):
                yield x
    if not topdown:
        yield top, dirs, nondirs

 实现的原理很简单,首先列出top文件夹下所有的文件(夹)的名字,names,然后遍历每一个name,来判断name是文件夹还是文件,分别放到不同的列表中。这时,yield语句出现了,这正是生成器的魔法所在。任何包含yield语句的函数,都被称作是生成器函数。如何理解这个表达式呢,可以把它看做是和return一样的功效,即让函数返回结果。事实上,yield并不是单纯的return,它将top,dirs,noddirs返回后,就冻结了,就是说,这个函数不会再次执行。那什么时候会恢复执行呢,就是当你再次去调用walk方法的时候,此时,函数被激活,继续执行。

yield并没有太大特别之处,只不过它能够使函数的执行被冻结,并且能够被激活再次进入运行状态。那么,os.walk()就不再神秘了。再次进入运行态后,就会进入 递归调用了,即 for x in walk(path.....): yield x 的功能。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics