排除os.walk中的目录


147

我正在编写一个脚本,该脚本会下降到目录树中(使用os.walk()),然后访问与某个文件扩展名匹配的每个文件。但是,由于我的工具将使用的某些目录树还包含子目录,这些子目录又包含很多无用的(出于此脚本的目的)内容,因此我想为用户添加一个选项以指定从遍历中排除的目录列表。

使用os.walk()很简单。毕竟,由我决定是我实际上是要访问os.walk()生成的相应文件/目录还是仅跳过它们。问题是,如果我有例如这样的目录树:

root--
     |
     --- dirA
     |
     --- dirB
     |
     --- uselessStuff --
                       |
                       --- moreJunk
                       |
                       --- yetMoreJunk

而且我想排除uselessStuff及其所有子项,os.walk()仍会进入uselessStuff的所有(可能成千上万个)子目录中,不用说,这会大大降低速度。在理想的世界中,我可以告诉os.walk()甚至不必费心再产生更多的uselessStuff,但是据我所知,这是没有办法的(是吗?)。

有人有主意吗?也许有一个第三方库提供了类似的东西?

Answers:


242

dirs 就地修改将修剪(以下)访问的(后续)文件和目录os.walk

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    dirs[:] = [d for d in dirs if d not in exclude]

从帮助(os.walk):

当topdown为true时,调用者可以就地修改目录名称列表(例如,通过del或slice分配),而walk仅会递归到名称保留在目录名称中的子目录中;这可以用来修剪搜索...


31
为什么dirs[:] =
ben

56
@ben:就地dirs[:] = value修改。它更改列表的内容而不更改容器。如前所述,如果您希望影响遍历子目录的方式,则需要这样做。(仅将变量重新分配(或“绑定”)到新列表,而无需修改原始列表。)dirs dirshelp(os.walk)os.walkdirs = valuedirsdirs
unutbu 2014年

6
您也可以使用filter()dirs[:] = list(filter(lambda x: not x in exclude, dirs))
NuclearPeon

2
@ p014k:您可以编写自己的生成器函数,该函数在从中排除(或您希望的其他任何东西)后调用os.walk并产生。root, dirs, files.gitdirs
unutbu 2015年

3
@unutbu只是让您知道,在一种情况下,此优化将遍历时间从100多秒减少到了大约2秒。这就是我所谓的有价值的优化。:D
antred

7

... @ unutbu出色答案的另一种形式,它的读入更为直接,因为其目的是排除目录,所花费的时间为O(n ** 2)vs O(n)。

list(dirs)为了正确执行,需要复制dirs列表)

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    [dirs.remove(d) for d in list(dirs) if d in exclude]

5
如果您希望以一些内存为代价进行更直接的处理,则最好编写dirs[:] = set(dirs) - exclude。至少它仍然是\ $ O(n)\ $,而您并不会仅仅因为其副作用而建立了理解……
301_Moved_Permanently

3
在我看来,这确实不错,但也不是惯用的Python。
Torsten Bronger '16

for d in list(dirs)有点奇怪。dirs已经是列表。而且,您所拥有的实际上并不是列表理解。dirs.remove(d)不返回任何内容,因此您最终得到一个包含Nones 的列表。我同意@Torsten。
seanahern
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.