这个 python 代码可以用列表理解来表达吗?

Can this python code be expressed with list comprehension?

我发现以下内容完全可读,但想知道它们是否是一种更像 python 的方式来完成它(也许是列表理解)?

import re
cgi_keys = [ '_None___total', '_George___total', 'Greg__total', '_Geoff___total', '_Gillian_total' ]
pattern = re.compile(r"_(.+)___(.+)")
totals = []
for key in cgi_keys:
    m = pattern.match(key)
    if m:
        totals.append(m.groups())
totals

将显示:

[('None', 'total'), ('George', 'total'), ('Geoff', 'total')]

但我希望我能想出一种方法来使用诸如以下的构造来获得上述内容:

[key for key in cgi_keys if pattern.match(key)]

以不太有用的形式显示字符串:

['_None___total', '_George___total', '_Geoff___total']

是否值得尝试将过滤后的字符串分解为元组或列表作为列表理解?

如果不为每个元素调用 pattern.match(key) 两次,就不能直接写成(单个)列表理解 - 即,

[pattern.match(key) for key in cgi_keys if pattern.match(key)]

但是,您可以通过使用生成器跳过 None 元素来稍微移动一下:

def skip_none(iter):
    return (i for i in iter if i is not None)

totals = skip_none(pattern.match(key) for key in cgi_keys)

实际上你可以使用:

totals = (pattern.match(key) for key in cgi_keys)
totals = [match.groups() for match in totals if match]

它更短但仍然有效,因为第一个影响是一个生成器,其值在第二个语句之前不会被评估。

此外,您可以使用:

totals = [match.groups for match in filter(None, map(pattern.match, cgi_keys))]

As map() 还给了一个发电机。您必须在 Python 2 中使用 imapifilter.

也是如此

请注意,如果 cgi_keys 真的很小,您也可以在 Python 2 中使用 map,因为通过迭代两次完成的额外工作可能无论如何都不会被注意到。

您可以在没有正则表达式的情况下执行此操作,并获取列表列表而不是元组。

[[v for v in cgi.split('_') if v] for cgi in cgi_keys]

结果:

[['None', 'total'], ['George', 'total'], ['Greg', 'total'], ['Geoff', 'total'], ['Gillian', 'total']]

但是如果你需要元组:

[tuple([v for v in cgi.split('_') if v]) for cgi in cgi_keys]