使用python3.4我试图过滤导出为JSON并转换为字典的防火墙规则库。我想根据用户定义的标准进行过滤,但是如果没有难以阅读的构造有很多循环和if语句,我似乎无法做到这一点。
我的防火墙条目中的字典很大,所以我把它们缩短了一点。
2个例子:
entry1 = {'action': 'accept',
'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}],
'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
entry2 = {'action': 'accept',
'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}],
'srcintf': [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'},
{'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'},
{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
我想创建一个数据结构来与2个示例进行比较,并创建如下:
filter = {'action': 'accept',
'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
在搜索了如何比较这些结构后,我最终得到了一些可读的代码。我的问题是它在entry2(它有多个源接口)时没有评估为true:
>>> filter.items() <= entry1.items()
True
>>> filter.items() <= entry2.items()
False
关于我应该如何做的任何提示?
编辑: 使用下面的答案Eric Duminil我可以创建一些东西(见下文),虽然它仍然没有我想要的那么可读。任何进一步的提示?
example = entry2
# Compare entry to filter
noMatch = 0
for key in filter:
if isinstance(example[key], list):
# Convert list of dicts to list for easier comparing
tmpExample = [d['name'] for d in example[key]]
# Break if entry does not contain all criteria
if not all(value in tmpExample for value in filter[key]):
noMatch = 1
print("No match on: " + str(filter[key]))
break
elif filter[key] != example[key]:
# Simple string comparing
noMatch = 1
print("No match on: " + str(filter[key]))
break
if noMatch == 0:
print("Match")
else:
print(" No match")
答案 0 :(得分:4)
'dstintf'
和'srcintf'
中的数据结构不会使此问题更容易。 dicts列表几乎不是正确的类型。
根据您的需要,您应该将其转换为字典:
>>> data = [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'},
... {'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'},
... {'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
>>> {d['q_origin_key']:d['name'] for d in data}
{'ZN_AUDIT': 'ZN_AUDIT', 'ZN_MGMT': 'ZN_MGMT', 'ZN_DMZ': 'ZN_DMZ'}
但如果name
和q_origin_key
的值始终相等,则可以使用列表或集合:
>>> [d['name'] for d in data]
['ZN_DMZ', 'ZN_MGMT', 'ZN_AUDIT']
>>> {d['name'] for d in data}
set(['ZN_AUDIT', 'ZN_MGMT', 'ZN_DMZ'])
现在过滤您的数据应该更容易,没有循环或if
s。
最后,dict.items()
以任意顺序返回元组列表。
我认为dict1.items() <= dict2.items()
无助于您做任何事情。
将代码拆分为多个函数并使用集合可能是个好主意:
query = {'action': 'accept',
'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
entry1 = {'action': 'accept',
'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}],
'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
entry2 = {'action': 'accept',
'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}],
'srcintf': [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'},
{'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'},
{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}]
}
def compare_values(value1, value2):
if isinstance(value1, list) and isinstance(value2, list):
return set(d['name'] for d in value1).issubset(set(d['name'] for d in value2))
else:
return value1 == value2
def is_a_match(query, entry):
do_not_match = [key for key in query if not compare_values(
query[key], entry.get(key))]
for key in do_not_match:
print("%r does not match" % key)
return len(do_not_match) == 0
print(is_a_match(query, entry1))
# True
print(is_a_match(query, entry2))
# True
print(is_a_match({'action': 'decline'}, entry2))
# 'action' does not match
# False