我需要列出当前目录(.)中的所有文件(包括所有子目录),并排除一些文件作为.gitignore的工作方式(http://git-scm.com/docs/gitignore
使用fnmatch(https://docs.python.org/2/library/fnmatch.html)我将能够使用模式“过滤”文件

ignore_files = ['*.jpg', 'foo/', 'bar/hello*']
matches = []
for root, dirnames, filenames in os.walk('.'):
  for filename in fnmatch.filter(filenames, '*'):
      matches.append(os.path.join(root, filename))

如何“筛选”并获取与“忽略文件”的一个或多个元素不匹配的所有文件?
谢谢!

最佳答案

你走的是正确的道路:如果你想使用fnmatch样式的图案,你应该使用fnmatch.filter来搭配它们。
但是有三个问题使得这个问题不那么简单。
首先,要应用多个筛选器。你是怎么做到的?多次呼叫filter

for ignore in ignore_files:
    filenames = fnmatch.filter(filenames, ignore)

第二,您实际上希望执行与filter相反的操作:返回不匹配的名称子集。如文件所述:
它与[n for n in names if fnmatch(n, pattern)]相同,但实现效率更高。
因此,要做相反的事情,你只需输入一个
for ignore in ignore_files:
    filenames = [n for n in filenames if not fnmatch(n, ignore)]

最后,您尝试对部分路径名进行筛选,而不仅仅是文件名,而是在筛选之后才进行not所以切换顺序:
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))

最后,如果您担心性能问题,可以对每个表达式使用join将它们转换为等效的regexp,然后将它们合并到一个大的regexp中并编译它,然后使用它而不是围绕fnmatch.translate循环。如果允许您的模式比fnmatch更复杂,这可能会变得很棘手,我建议您不要这样做,除非您确实在这里确定了性能瓶颈。但是如果你需要这样做的话,我至少看到了一个问题,在这个问题上,有人花了很大的精力去解决所有的边缘问题,所以搜索而不是自己写。

关于python - Python,如何实现类似.gitignore行为的东西,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25229592/

10-13 06:43