有两个决定:旧的和更新的。我想检查一下它们是否相等,除了status
,latitude
和longitude
键之外。
assert old_dict['status'] != updated_dict['status']
assert old_dict['latitude'] != updated_dict['latitude']
assert old_dict['longitude'] != updated_dict['longitude']
for field in ('status', 'latitude', 'longitude'):
updated_dict.pop(field)
old_dict.pop(field)
assert old_dict == updated_dict
执行此操作的更Python方式是什么?
答案 0 :(得分:3)
您可以断言,两个字典的项之间的对称差异是三个键的区别:
assert {k for k, _ in old_dict.items() ^ updated_dict.items()} == {'status', 'latitude', 'longitude'}
答案 1 :(得分:2)
有点不合常规的建议,但是请听我说:
differing = {"status", "latitude", "longitude"}
assert all(
(old_dict[key] != updated_dict[key]) == (key in differing)
for key in old_dict
)
对于每个key
,我们断言,当且仅当键是不同的键之一时,值才不同。
答案 2 :(得分:1)
您可以通过字典理解过滤两个字典,然后检查是否相等:
def compare_dicts(d1, d2, exc_keys):
dct1 = {k: v for k, v in d1.items() if k not in exc_keys}
dct2 = {k: v for k, v in d2.items() if k not in exc_keys}
return dct1 == dct2
assert compare_dicts(old_dict, updated_dict, {'status', 'latitude', 'longitude'})
答案 3 :(得分:1)
我认为完整测试要求 exception 或excluded
dict键必须不同,并且两个词典可能没有相同的所有键。
一些测试用例可以这样写:
import string
import random
random.seed(0)
keys = list(string.ascii_letters)
excluded = 'r', 'm', 'e'
# the original dict
base_dict = {key: random.randint(1, 100) for key in keys}
# some keys, different from excluded are different
unequal_dict = {key: (val if key not in ('q') else random.randint(1, 100)) for key, val in base_dict.items()}
# only the excluded keys are different
equal_dict = {key: (val if key not in excluded else random.randint(1, 100)) for key, val in base_dict.items()}
# only some of the excluded keys are different
partial_dict = {key: (val if key not in excluded[1:] else random.randint(1, 100)) for key, val in base_dict.items()}
# a copy of the base dict
identical_dict = base_dict.copy()
# one more key is added
not_same_keys_dict = base_dict.copy()
not_same_keys_dict['aa'] = 1
现在old_dict
基本上是base_dict
,而unequal_dict
,equal_dict
,partial_dict
,identical_dict
和not_same_keys_dict
涵盖了不同的地方极端情况。
然后,我们定义一些辅助函数,以一次测试不同的输入。
def multi_test(func, many_args):
return [func(*args) for args in many_args]
many_args = (
(base_dict, unequal_dict, updated),
(base_dict, equal_dict, updated),
(base_dict, partial_dict, updated),
(base_dict, identical_dict, updated),
(base_dict, not_same_keys_dict, updated))
原始代码的功能如下:
import copy
def dicts_equal_except_orig(dict1, dict2, excluded):
dict1 = dict1.copy()
dict2 = dict2.copy()
result = True
for key in excluded:
result = result and (dict1[key] != dict2[key])
dict1.pop(key)
dict2.pop(key)
result = result and (dict1 == dict2)
return result
print(multi_test(dicts_equal_except_orig, many_args))
# [False, True, False, False, False]
%timeit multi_test(dicts_equal_except_orig, many_args)
# 13.1 µs ± 183 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
在要比较的字典具有一些不共通的键的假设下,这几乎与完成的测试所能达到的速度一样快。
所有其他方法的运行速度虽然要慢得多,但可能会更清洁,在某些情况下,例如,甚至可能更快。当要排除的键数很大时,等等。
另外,如果不需要not_same_key
用例,即字典始终具有相同的键,则基于all()
的解决方案将更快,因为它们将具有明显的短路,并且它们可以通过以下方式进行转换:
keys = dict1.keys() | dict2.keys()
例如
keys = dict1.keys()
并删除其他if key in dict1 and key in dict2
等健全性检查。
为完整起见,我报告了我测试过的所有其他选项:
def dicts_equal_except(dict1, dict2, excluded):
keys = dict1.keys() | dict2.keys()
return all(
(dict1[key] != dict2[key] if key in excluded else dict1[key] == dict2[key])
if key in dict1 and key in dict2 else False
for key in keys)
print(multi_test(dicts_equal_except, many_args))
# [False, True, False, False, False]
%timeit multi_test(dicts_equal_except, many_args)
# 28.3 µs ± 186 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def check_dict_except(dict1, dict2, excluded):
return {k for k, _ in dict1.items() ^ dict2.items()} == set(excluded)
print(multi_test(check_dict_except, many_args))
# [False, True, False, False, False]
%timeit multi_test(check_dict_except, many_args)
# 30.8 µs ± 498 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def dicts_equal_all(dict1, dict2, excluded):
keys = dict1.keys() | dict2.keys()
return all((dict1[key] == dict2[key]) ^ (key in excluded) for key in keys)
print(multi_test(dicts_equal_all, many_args))
# [False, True, False, False, False]
%timeit multi_test(dicts_equal_all, many_args)
# 29.7 µs ± 316 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
和
def dicts_equal_all2(dict1, dict2, excluded):
keys = dict1.keys() | dict2.keys()
return all((dict1[key] != dict2[key]) == (key in excluded) for key in keys)
print(multi_test(dicts_equal_all2, many_args))
# [False, True, False, False, False]
%timeit multi_test(dicts_equal_all2, many_args)
# 29.9 µs ± 435 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def compare_dicts(dict1, dict2, excluded):
filter_dict1 = {key: val for key, val in dict1.items() if key not in excluded}
filter_dict2 = {key: val for key, val in dict2.items() if key not in excluded}
excluded_dict1 = {key: dict1[key] for key in excluded if key in dict1}
excluded_dict2 = {key: dict2[key] for key in excluded if key in dict2}
return filter_dict1 == filter_dict2 and all(dict1[key] != dict2[key] if key in dict1 and key in dict2 else False for key in excluded)
print(multi_test(compare_dicts, many_args))
# [False, True, False, False, False]
%timeit multi_test(compare_dicts, many_args)
# 57.5 µs ± 960 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
答案 4 :(得分:0)
尝试一下:
old_dict.keys() == updated_dict.keys()
如果old_dict
键是update_dict
键的子集,则为true。
答案 5 :(得分:0)
几行,但是应该很快,因为它不会改变要比较的字典对的结构。
EXC = {"status", "latitude", "longitude"}
saved = {}
for key in EXC:
saved[key], updated_dict[key] = updated_dict[key], old_dict[key]
cmp = old_dict == updated_dict
for key in EXC:
old_dict[key], updated_dict[key] = updated_dict[key], saved[key]
答案 6 :(得分:0)
怎么样
ignore = {'status', 'latitude', 'longitude'}
equal = all([old_value == new[key]
for key, old_value in old.items()
if key not in ignore])
这一次遍历字典(我认为没有办法解决这个问题)。