Python遍历目录树的方式是什么?

Python遍历目录树的方式是什么?,python,directory-walk,Python,Directory Walk,我觉得分配文件和文件夹以及做+=[item]部分有点老土。有什么建议吗?我正在使用Python 3.2 from os import * from os.path import * def dir_contents(path): contents = listdir(path) files = [] folders = [] for i, item in enumerate(contents): if isfile(contents[i]):

我觉得分配文件和文件夹以及做+=[item]部分有点老土。有什么建议吗?我正在使用Python 3.2

from os import *
from os.path import *

def dir_contents(path):
    contents = listdir(path)
    files = []
    folders = []
    for i, item in enumerate(contents):
        if isfile(contents[i]):
            files += [item]
        elif isdir(contents[i]):
            folders += [item]
    return files, folders
看看这个函数,它返回路径及其包含的目录和文件。这将大大缩短您的解决方案。

尝试使用该方法。

确实使用

items += [item]
因为很多原因,它是不好的

  • append
    方法就是为此而制定的方法(将一个元素追加到列表末尾)

  • 您正在创建一个元素的临时列表,只是为了将其丢弃。虽然在使用Python时,原始速度不应该是您首先关心的问题(否则您使用的是错误的语言),但仍然无缘无故地浪费速度似乎是不对的

  • 您使用的Python语言有点不对称。。。对于列表对象,写入
    a+=b
    与写入
    a=a+b
    不同,因为前者修改对象的位置,而第二个则分配一个新列表,如果对象
    a
    也可以通过其他方式访问,则这可能具有不同的语义。在您的特定代码中,情况似乎并非如此,但当其他人(或几年后的您)不得不修改代码时,这可能会成为一个问题。Python甚至有一个方法
    extend
    ,它的语法不太精细,专门用于处理您希望通过在另一个列表的末尾添加元素来就地修改列表对象的情况


  • 另外,正如其他人所注意到的,您的代码似乎正在尝试做
    os.walk
    已经做过的事情…

    而不是内置的os.walk和os.path.walk,我使用的是从我在别处找到的这段代码中派生出来的东西,我最初链接到这段代码,但已替换为内联源代码:

    import os
    import stat
    
    class DirectoryStatWalker:
        # a forward iterator that traverses a directory tree, and
        # returns the filename and additional file information
    
        def __init__(self, directory):
            self.stack = [directory]
            self.files = []
            self.index = 0
    
        def __getitem__(self, index):
            while 1:
                try:
                    file = self.files[self.index]
                    self.index = self.index + 1
                except IndexError:
                    # pop next directory from stack
                    self.directory = self.stack.pop()
                    self.files = os.listdir(self.directory)
                    self.index = 0
                else:
                    # got a filename
                    fullname = os.path.join(self.directory, file)
                    st = os.stat(fullname)
                    mode = st[stat.ST_MODE]
                    if stat.S_ISDIR(mode) and not stat.S_ISLNK(mode):
                        self.stack.append(fullname)
                    return fullname, st
    
    if __name__ == '__main__':
        for file, st in DirectoryStatWalker("/usr/include"):
            print file, st[stat.ST_SIZE]
    

    它以递归方式遍历目录,非常高效且易于阅读。

    在搜索相同的信息时,我发现了这个问题

    我在这里发布了我在网站上找到的最小、最清晰的代码(而不是仅仅发布URL,以防链接腐烂)

    该页面有一些有用的信息,还指向一些其他相关页面

    # Import the os module, for the os.walk function
    import os
    
    # Set the directory you want to start from
    rootDir = '.'
    for dirName, subdirList, fileList in os.walk(rootDir):
        print('Found directory: %s' % dirName)
        for fname in fileList:
            print('\t%s' % fname)
    

    我还没有对此进行过广泛的测试,但我相信 这将展开
    os.walk
    生成器,将dirnames连接到所有文件路径,并展平结果列表;提供搜索路径中具体文件的直接列表

    import itertools
    import os
    
    def find(input_path):
        return itertools.chain(
            *list(
                list(os.path.join(dirname, fname) for fname in files)
                for dirname, _, files in os.walk(input_path)
            )
        )
    

    如果您想递归地遍历所有文件,包括子文件夹中的所有文件,我相信这是最好的方法

    import os
    
    def get_files(input):
        for fd, subfds, fns in os.walk(input):
           for fn in fns:
                yield os.path.join(fd, fn)
    
    ## now this will print all full paths
    
    for fn in get_files(fd):
        print(fn)
    

    自Python 3.4以来,出现了新的模块pathlib。因此,要获取所有目录和文件,可以执行以下操作:

    from pathlib import Path
    
    dirs = [str(item) for item in Path(path).iterdir() if item.is_dir()]
    files = [str(item) for item in Path(path).iterdir() if item.is_file()]
    

    os.walk
    os.scandir
    是很好的选择,但是,我已经越来越多地使用pathlib,使用pathlib,您可以使用
    .glob()
    方法:

    root_directory = Path(".")
    for path_object in root_directory.glob('**/*'):
        if path_object.is_file():
            print(f"hi, I'm a file: {path_object}")
        elif path_object.is_dir():
            print(f"hi, I'm a dir: {path_object}")
    
    
    

    适用于使用
    pathlib
    python>=3.4
    )寻找解决方案的任何人


    但是,如上所述,这并没有保留操作系统提供的自上而下的顺序。walk

    哇,太完美了,真不敢相信我错过了。谢谢。但是
    os.walk
    并不像OP的代码那样局限于一个目录级别。避免从x导入
    *
    。这是对Pythonic风格的一条建议。这种向列表中添加项目的方式也很不成熟。添加带有
    文件的单个项目。附加(项目)
    或带有
    文件的多个项目。扩展([item1,item2,…])
    +1:这也比
    列表+=[item]
    好得多。电池包括在内,熟悉核心语言功能会阻止你重新发明电池:+1@mikebabcock谢谢-这在Python 2.x中对我来说是开箱即用的(即使OP使用的是3.x),我需要一个2.x解决方案。不幸的是,该项目不再可用,404。有人可以在这里重新编写吗?我还没有检查它是否相同,但是cf@LarsHI非常喜欢这种方法,因为它将文件系统迭代代码与处理每个文件的代码分开!但是,需要省略“yield from”行-
    os.walk
    已经进入子目录,因此如果您也这样做,您会看到子目录文件2^n次。iterdir()不会递归地遍历树。但是。。。pathlib确实支持递归全局搜索。方法
    iterdir()
    方法
    os.walk()
    。我对尝试重新实现那个久经考验的方法极为缄默。(注意:有些方法,如
    os.rmdir()
    只能删除空目录,因此顺序可能非常重要。)但是,os.walk已经为您分离了文件和目录。另外,刚刚记住:对于os.walk,如果我将自上而下设置为True(默认),我可以操作子目录列表,例如,跳过整个子树。请参见文档中关于大树中**的注释。我希望os.walk能够返回路径对象。(愚蠢的5分钟编辑限制)我在这里的评论将保留新行。
    root_directory = Path(".")
    for path_object in root_directory.glob('**/*'):
        if path_object.is_file():
            print(f"hi, I'm a file: {path_object}")
        elif path_object.is_dir():
            print(f"hi, I'm a dir: {path_object}")
    
    
    
    from pathlib import Path
    
    def walk(path): 
        for p in Path(path).iterdir(): 
            if p.is_dir(): 
                yield from walk(p)
                continue
            yield p.resolve()
    
    # recursively traverse all files from current directory
    for p in walk(Path('.')): 
        print(p)
    
    # the function returns a generator so if you need a list you need to build one
    all_files = list(walk(Path('.')))