Это на самом деле довольно интересная проблема. Вы можете определить список преобразований, например, в форме (key1, func_1to2, key2, func_2to1)
или в аналогичном формате, где key
может содержать разделители для обозначения различных уровней dict, например "Person.name.first"
.
noop = lambda x: x
relations = [("Person.name.first", noop, "Person.firstname", noop),
("Person.name.last", noop, "Person.lastname", noop),
("birth_date", lambda s: datetime.date(*map(int, s.split("."))),
"Person.birth", lambda d: d.strftime("%Y.%m.%d")),
("points", int, "Person.points", str)]
Затем выполните итерацию элементов в этом списке и преобразуйте записи в словаре в зависимости от того, хотите ли вы перейти от формы A к B или наоборот. Вам также понадобится некоторая вспомогательная функция для доступа к ключам во вложенных словарях с использованием этих разделенных точками ключей.
def deep_get(d, key):
for k in key.split("."):
d = d[k]
return d
def deep_set(d, key, val):
*first, last = key.split(".")
for k in first:
d = d.setdefault(k, {})
d[last] = val
def convert(d, mapping, atob):
res = {}
for a, x, b, y in mapping:
a, b, f = (a, b, x) if atob else (b, a, y)
deep_set(res, b, f(deep_get(d, a)))
return res
Пример:
>>> d1 = {"Person": { "name": { "first": "John", "last": "Smith" } },
... "birth_date": "1997.01.12",
... "points": "330" }
...
>>> print(convert(d1, relations, True))
{'Person': {'birth': datetime.date(1997, 1, 12),
'firstname': 'John',
'lastname': 'Smith',
'points': 330}}