Sunday, August 15, 2010

递归, 循环, 迭代

工作中, 需要有历遍目录进行一些操作. python自带的os.walk很强大, 但是没有maxdepth这种层数参数.

os.walk是原本是一个递归. 下面是它的代码:
273     try:
274         # Note that listdir and error are globals in this module due
275         # to earlier import-*.
276         names = listdir(top)
277     except error, err:
278         if onerror is not None:
279             onerror(err)
280         return
281
282     dirs, nondirs = [], []
283     for name in names:
284         if isdir(join(top, name)):
285             dirs.append(name)
286         else:
287             nondirs.append(name)
288
289     if topdown:
290         yield top, dirs, nondirs
291     for name in dirs:
292         path = join(top, name)
293         if followlinks or not islink(path):
294             for x in walk(path, topdown, onerror, followlinks):
295                 yield x
296     if not topdown:
297         yield top, dirs, nondirs

BTW:: 这里需要注意*nux的ENAMETOOLONG 错误.

递归无法按"层"历遍目录. 它只能一条一条路径走尽.

朋友说使用循环也可以实现递归, 这种代码从来没有写过. 也一直在迷惑。
但是受 http://www.devshed.com/c/a/Python/Basic-Threading-in-Python/2/ 的启发.
突然明白循环是怎么做到递归的。 于是自己使用循环自己写了一个历遍的函数:

def loop_walk(top, n):
    stack = Queue.Queue()
    sub_stack = Queue.Queue()
    dirs = []
    files = []
    error = None
    stack.put([top])
    
    while True:
        if stack.empty():
            # stack被取完了, 下一层队列
            stack, sub_stack = sub_stack, stack
            if n <= 1:
                yield [], [], None
                return
            else:
                n -= 1
            continue
        else:
            try:
                top_list = stack.get(False)
            except Queue.Empty:
                yield [], [], None
                return

        for top in top_list:
            try:
                for item in os.listdir(top):
                    item = os.path.join(top, item)
                    if os.path.isdir(item):
                        dirs.append(item)
                    else:
                        files.append(item)
            except:
                # 出错, 比如没有权限
                #traceback.print_exc()
                error = top
            yield dirs, files, error
            if dirs:
                sub_stack.put(dirs)
            dirs = []
            files = []
            error = None

代码长度double了.........

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.