你走在正确的轨道上:如果你想使用fnmatch
-style 模式,你应该使用fnmatch.filter
它们。
但是有三个问题使这不是微不足道的。
首先,您要应用多个过滤器。你是怎样做的?filter
多次调用:
for ignore in ignore_files:
filenames = fnmatch.filter(filenames, ignore)
其次,您实际上想要执行相反的操作:返回不匹配filter
的名称子集。正如文档所解释的:
它与 相同[n for n in names if fnmatch(n, pattern)]
,但执行效率更高。
因此,相反,您只需输入一个not
:
for ignore in ignore_files:
filenames = [n for n in filenames if not fnmatch(n, ignore)]
最后,您尝试过滤部分路径名,而不仅仅是文件名,但join
直到过滤后您才这样做。所以切换顺序:
filenames = [os.path.join(root, filename) for filename in filenames]
for ignore in ignore_files:
filenames = [n for n in filenames if not fnmatch(n, ignore)]
matches.extend(filenames)
有几种方法可以改善这一点。
您可能希望使用生成器表达式而不是列表推导(括号而不是方括号),因此如果您有大量文件名列表,则您使用的是惰性管道,而不是浪费时间和空间重复构建庞大的列表。
此外,如果您颠倒循环的顺序,可能会也可能不会更容易理解,如下所示:
filenames = (n for n in filenames
if not any(fnmatch(n, ignore) for ignore in ignore_files))
最后,如果您担心性能,您可以使用fnmatch.translate
每个表达式将它们转换为等效的正则表达式,然后将它们合并为一个大的正则表达式并编译它,并使用它而不是循环fnmatch
。如果您的模式被允许比 更复杂,这可能会变得很棘手*.jpg
,除非您确实在这里确定了性能瓶颈,否则我不会推荐它。但是,如果您需要这样做,我已经看到至少一个关于 SO 的问题,有人付出了很多努力来敲定所有边缘情况,因此请搜索而不是尝试自己编写。