Большая часть проблемы в том, что у вас нет правильной спецификации для вложенных ключей.Очевидно, вы не можете индексировать строку с другой строкой, поэтому 'C'['lastElement']
не даст вам ничего, кроме ошибки.Давайте использовать кортеж или другую итерацию для хранения вложенных ключей:
equal_dicts(data1, data2, ('A', ('C', 'lastElement')))
Теперь довольно легко очистить словари:
def remove_key(d, k):
if not isinstance(d, dict): return
try:
if isinstance(k, str) or len(k) == 1:
if not isinstance(k, str): k = k[0]
del d[k]
else:
remove_key(d[k[0]], k[1:])
except KeyError:
pass
Просто используйте эту функцию вместо del
.
Имейте в виду, что сделанная вами копия мелкая: удаление вложенных ключей фактически удалит их и из исходных объектов.Вы можете противодействовать этому, обновив функцию remove_key
, чтобы она возвращала обновленный словарь по мере необходимости только при удалении ключа.Это не будет намного дешевле, чем, скорее всего, сделать глубокую копию, но ее будет немного легче читать:
def remove_key(d, key):
if not isinstance(d, dict):
return d
if not isinstance(key, str):
key, *rem = key
else:
rem = []
if key not in d:
return d
if not rem:
return {k: v for k, v in d.items() if k != key}
e = remove_key(d[key], rem)
if e is not d[key]:
return {k: e if k == key else v for k, v in d.items()}
return d
Используйте эту версию для назначения копий:
for key in ignore_keys:
d1 = remove_key(d1, key)
d2 = remove_key(d2, key)
Если ключ не будет удален, он останется исходной ссылкой.Любой удаленный ключ вызовет копирование только необходимых уровней вложенного словаря, хотя это может произойти несколько раз для данного уровня.
В качестве окончательного возвращаемого значения просто используйте return d1 == d2
.Сравнение по словарю осуществляется по фактическому ключу и значению без учета сортировки.