使用不同过滤器针对同一个列表处理多个 for 循环的 Pythonic 方法?

Posted

技术标签:

【中文标题】使用不同过滤器针对同一个列表处理多个 for 循环的 Pythonic 方法?【英文标题】:Pythonic way to process multiple for loops with different filters against the same list? 【发布时间】:2015-08-10 02:09:38 【问题描述】:

这是我正在编写的一个程序,它将创建一个对文件目录进行分类的 csv:

matches = []
for root, dirnames, filenames in os.walk(directory):
    for filename in fnmatch.filter(filenames, '*[A-Z]*'):
        matches.append([os.path.join(root, filename), "No Capital Letters!"])

    test = re.compile(".*\.(py|php)", re.IGNORECASE)
    for filename in filter(test.search, filenames):
        matches.append([os.path.join(root, filename), "Invalid File type!"])

基本上,用户选择一个文件夹,程序表示有问题的文件,可以有多种类型(这里只列出两种:没有大写字母的文件,没有 php 或 python 文件)。大概会有五六个案例。

虽然这可行,但我想重构。有没有可能做类似的事情

for filename in itertools.izip(fnmatch.filter(filenames, '*[A-Z]*'), filter(test.search, filenames), ...):
    matches.append([os.path.join(root, filename), "Violation")

同时能够跟踪哪些原始解压缩列表导致了“违规”?

【问题讨论】:

【参考方案1】:

我建议你看看these slides。

David Beazley 给出了一个使用yield 处理日志文件的示例。

编辑:这里有两个来自 pdf 的例子,一个没有生成器:

wwwlog = open("access-log")
total = 0
for line in wwwlog:
  bytestr = line.rsplit(None,1)[1]
   if bytestr != '-':
     total += int(bytestr)
 print "Total", total

and with generator(对于更复杂的示例,可以使用带有 yield 的函数)

wwwlog = open("access-log")
bytecolumn = (line.rsplit(None,1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)

【讨论】:

已更新示例。同意的仅链接答案不太好。【参考方案2】:

一个更简单的解决方案可能是先遍历文件,然后逐个应用检查:

reTest = re.compile(".*\.(py|php)", re.IGNORECASE)
for root, dirnames, filenames in os.walk(directory):
    for filename in filenames:
        error = None
        if fnmatch.fnmatch(filename, '*[A-Z]*'):
            error = 'No capital letters!'
        elif reTest.search(filename):
            error = 'Invalid file type!'

        if error:
            matches.append([os.path.join(root, filename), error])

这不仅会使逻辑更简单,因为您只需要检查一个文件(而不是每次都必须弄清楚如何在文件名序列上调用您的检查方法),它还将只进行迭代一次通过文件名列表。

此外,它还将避免为单个文件名生成多个匹配项;它最多只会添加一个错误(第一个)。如果您不希望这样,您可以将 error 设为一个列表,并在您的检查中附加到它 - 当然您希望将 elif 更改为 if 然后评估所有检查。

【讨论】:

以上是关于使用不同过滤器针对同一个列表处理多个 for 循环的 Pythonic 方法?的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本--------for循环

Shell脚本

Shell脚本 for循环 while循环 case分支语句

Django框架模版渲染与过滤器使用

for循环语句#yyds干货盘点#

使用 for 循环和过滤器优化代码