我试图编写一个递归删除所有空目录的Python函数。这意味着如果目录" a"仅包含" b"," b"应删除,然后" a"应删除(因为它现在不包含任何内容)。如果目录包含任何内容,则会跳过该目录。所示:
top/a/b/
top/c/d.txt
top/c/foo/
鉴于此,三个目录" b"," a"和" foo"应删除,因为" foo"和" b"现在是空的," a"删除" b"。
后将变为空我尝试通过os.walk
和shutil.rmtree
执行此操作。不幸的是,我的代码只删除了第一级目录,但没有删除过程中新清空的目录。
我正在使用topdown=false
的{{1}}参数。 os.walk
os.walk
表示"如果topdown为False,则在所有子目录的三元组(目录是自下而上生成)之后生成目录的三元组。&#34 ;那不是我所看到的。
这是我的代码:
for root, dirs, files in os.walk(".", topdown=False):
contents = dirs+files
print root,"contains:",contents
if len(contents) == 0:
print 'Removing "%s"'%root
shutil.rmtree(root)
else:
print 'Not removing "%s". It has:'%root,contents
如果我有上述目录结构,请参阅以下内容:
./c/foo contains: []
Removing "./c/foo"
./c contains: ['foo', 'd.txt']
Not removing "./c". It has: ['foo', 'd.txt']
./a/b contains: []
Removing "./a/b"
./a contains: ['b']
Not removing "./a". It has: ['b']
. contains: ['c', 'a']
Not removing ".". It has: ['c', 'a']
请注意,即使我已删除" b"," a"没有删除,认为它仍然包含" b"。我感到困惑的是,os.walk
的文档说它会为" ./ a"生成三元组。 生成" b"的三元组后。我的输出表明不然。类似的故事为" ./ c"。它表明它仍然有" foo",即使我已经将它从门外删除了。
我做错了什么? (我使用的是Python 2.6.6。)
答案 0 :(得分:9)
documentation有这个......
无论topdown的值如何,子目录列表都是 在目录及其子目录的元组之前检索 生成。
答案 1 :(得分:2)
jcfollower的答案对于您遇到的问题的原因绝对正确:文件系统始终自上而下读取,即使结果是从底部的os.walk
得出的的方式。这意味着您执行的文件系统修改不会反映在后面的结果中。
此问题的解决方案是维护一组已删除的目录,以便您可以从父目录的子目录列表中过滤它们:
removed = set() # first new line
for root, dirs, files in os.walk(".", topdown=False):
dirs = [dir for dir in dirs if os.path.join(root, dir) not in removed] # second
contents = dirs+files
print root,"contains:",contents
if len(contents) == 0:
print 'Removing "%s"'%root
shutil.rmtree(root)
removed.add(root) # third new line
else:
print 'Not removing "%s". It has:'%root,contents
有三条新线。第一个,在顶部,创建一个空removed
集以包含已删除的目录。第二个替换dirs
列表的新列表不包含已删除集中的任何子目录,因为它们在上一步中被删除。最后一个新行将当前目录添加到已删除的集合中。