【问题标题】:Does os.walk() use recursion or iteration? [duplicate]os.walk() 使用递归还是迭代? [复制]
【发布时间】:2016-11-19 01:42:08
【问题描述】:

好的,我看到有人说 Python 中的 os.walk() 使用递归,有人说它使用迭代。正确答案是什么?

【问题讨论】:

  • 查找函数源代码?
  • 你自己搜的吗?
  • 首先,它可能两者兼而有之。其次,你为什么关心这个实现细节?
  • 从技术上讲,它同时使用了两者。这是一个纯python模块,所以你可以阅读source in python

标签: python recursion iteration os.walk


【解决方案1】:

来自 WinPython-64bit-3.5.1.3 ~/lib/os.py... 是递归的

def walk(top, topdown=True, onerror=None, followlinks=False):

    dirs = []
    nondirs = []

    # We may not have read permission for top, in which case we can't
    # get a list of the files the directory contains.  os.walk
    # always suppressed the exception then, rather than blow up for a
    # minor reason when (say) a thousand readable directories are still
    # left to visit.  That logic is copied here.
    try:
        # Note that scandir is global in this module due
        # to earlier import-*.
        scandir_it = scandir(top)
    except OSError as error:
        if onerror is not None:
            onerror(error)
        return

    while True:
        try:
            try:
                entry = next(scandir_it)
            except StopIteration:
                break
        except OSError as error:
            if onerror is not None:
                onerror(error)
            return

        try:
            is_dir = entry.is_dir()
        except OSError:
            # If is_dir() raises an OSError, consider that the entry is not
            # a directory, same behaviour than os.path.isdir().
            is_dir = False

        if is_dir:
            dirs.append(entry.name)
        else:
            nondirs.append(entry.name)

        if not topdown and is_dir:
            # Bottom-up: recurse into sub-directory, but exclude symlinks to
            # directories if followlinks is False
            if followlinks:
                walk_into = True
            else:
                try:
                    is_symlink = entry.is_symlink()
                except OSError:
                    # If is_symlink() raises an OSError, consider that the
                    # entry is not a symbolic link, same behaviour than
                    # os.path.islink().
                    is_symlink = False
                walk_into = not is_symlink

            if walk_into:
                yield from walk(entry.path, topdown, onerror, followlinks)

    # Yield before recursion if going top down
    if topdown:
        yield top, dirs, nondirs

        # Recurse into sub-directories
        islink, join = path.islink, path.join
        for name in dirs:
            new_path = join(top, name)
            # Issue #23605: os.path.islink() is used instead of caching
            # entry.is_symlink() result during the loop on os.scandir() because
            # the caller can replace the directory entry during the "yield"
            # above.
            if followlinks or not islink(new_path):
                yield from walk(new_path, topdown, onerror, followlinks)
    else:
        # Yield after recursion if going bottom up
        yield top, dirs, nondirs

见yield from walk(...声明

【讨论】:

    【解决方案2】:

    它是递归的 - 请参阅https://docs.python.org/2/library/os.html#os.walk 中的注释。如果您查看源代码(例如,https://svn.python.org/projects/python/trunk/Lib/os.py),您将看到 walk() 函数在其内部被调用:

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

    【讨论】:

      猜你喜欢
      • 2011-09-21
      • 2011-05-23
      • 2012-06-16
      • 2015-03-24
      • 2012-04-18
      • 2014-03-24
      • 2012-06-25
      相关资源
      最近更新 更多