我正在尝试编写一个Python函数,它将递归删除所有空目录.这意味着如果目录"a"仅包含"b",则应删除"b",则应删除"a"(因为它现在不包含任何内容).如果目录包含任何内容,则会跳过该目录.图说:
top/a/b/
top/c/d.txt
top/c/foo/
Run Code Online (Sandbox Code Playgroud)
鉴于此,应删除三个目录"b","a"和"foo",因为"foo"和"b"现在为空,并且"a"在删除"b"后将变为空.
我试图通过os.walk
和shutil.rmtree
.不幸的是,我的代码只删除了第一级目录,但没有删除过程中新清空的目录.
我正在使用topdown=false
参数os.walk
.该文档的os.walk
说:"如果自上而下为False,三联供的目录是三元的所有子目录后生成(目录生成由下而上)." 那不是我所看到的.
这是我的代码:
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
Run Code Online (Sandbox Code Playgroud)
如果我有上面描述的目录结构,这是我得到的:
./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']
Run Code Online (Sandbox Code Playgroud)
请注意,即使我删除了"b",也没有删除"a",认为它仍然包含"b".令我困惑的是,文档os.walk
说它在为"b"生成三元组后生成"./a" 的三元组.我的输出表明不然.类似的故事为"./c".它表明它仍然有"foo",即使我已经将它删除了.
我究竟做错了什么?(我使用的是Python 2.6.6.)
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
Run Code Online (Sandbox Code Playgroud)
有3条新线路。第一个在顶部创建一个空removed
集来包含已删除的目录。第二个将dirs
列表替换为新列表,该列表不包含已删除集中的任何子目录,因为它们已在上一步中删除。最后一个新行将当前目录添加到已删除的集合中。