我在使用Dict和列表理解作为案例陈述时遇到了麻烦。我只想要第一场比赛 - 但我得到了所有的比赛。这个词典很长,但看起来很明显:
categories = { 'rhsa' : 'Red Hat',
'red hat' : 'Red Hat',
'.net' : 'Microsoft .Net',
'sql server' : 'MS SQL',
'microsoft' : 'Microsoft',
etc..}
功能很简单:
def vuln_category(vuln_title):
vuln_cat = ''
vuln_title = vuln_title.lower()
try:
vuln_cat = ''.join([categories[k] for k in categories if (k in vuln_title and len(vuln_cat)==0)]) # ''.join() to convert to string
if vuln_cat == '':
vuln_cat = 'Other'
except KeyError:
vuln_cat = 'Other'
return vuln_cat
我得到的是“第三方SoftwareVMWareMicrosoftVMWare”。很明显,“and len(vuln_cat)== 0”没有像我预期的那样在循环中进行评估,导致每个类别匹配连接dict值。
是的,我可以(并且已经)将它编码为嵌套循环作为一个简单的修复,但我想知道解决这个问题的正确方法。
Python版本是3.4。我试图保持这个简单,因为它是一个令人讨厌的剧本。
答案 0 :(得分:2)
vuln_cat
只有在列表理解完成后设置,您才能从理解中访问正在构建的列表。
使用generator expression内的next()
function代替,这只会选择第一个匹配结果:
def vuln_category(vuln_title):
vuln_title = vuln_title.lower()
return next(
(categories[k] for k in categories if k in vuln_title),
'Other')
next()
函数的第二个参数是默认值,如果生成器表达式没有产生任何结果,则使用该参数。
演示:
>>> categories = {
... 'rhsa': 'Red Hat',
... 'red hat': 'Red Hat',
... '.net': 'Microsoft .Net',
... 'sql server': 'MS SQL',
... 'microsoft': 'Microsoft',
... }
>>> def vuln_category(vuln_title):
... vuln_title = vuln_title.lower()
... return next(
... (categories[k] for k in categories if k in vuln_title),
... 'Other')
...
>>> vuln_category('Microsoft SQL Server on .NET')
'MS SQL'
>>> vuln_category('Red Hat RHSA')
'Red Hat'
>>> vuln_category('Mac OS X')
'Other'