TLDR
Вы можете использовать dict.setdefault
или collections.defaultdict
.
def make_path(d: dict, *paths: str) -> None:
for key in paths:
d = d.setdefault(key, {})
make_path(my_dict, 'path-to', 'my', 'keys')
assert my_dict['path-to']['my']['keys'] is not None
Полная информация
Решение 1. dict.setdefault
:
my_dict.setdefault('path-to', {}).setdefault('my', {}).setdefault('keys', {})
Плюсы:
my_dict
нормально dict
- диктовка происходит только явно
- Нет ограничений по глубине
Минусы:
- Вы должны вызывать
setdefault
метод при каждом использовании.
Решение 2. collections.defaultdict
:
from collections import defaultdict
my_dict = defaultdict(lambda: defaultdict(lambda: defaultdict(dict)))
my_dict['path-to']['my']['keys']
Плюсы:
- Вам не нужно звонить проверять существование вообще.
Минусы:
- Создание словаря происходит неявно.
my_dict
не является чистым dict
. - У вас есть ограничение по глубине по определению
my_dict
.
Решение 3. Усовершенствовано из решения 1: Создайте свою собственную функцию
def make_path(my_dict: dict, *paths: str) -> dict:
while paths:
key, *paths = paths
my_dict = my_dict.setdefault(key, {})
return my_dict
test = {'path-to': {'test': 1}}
print(test)
make_path(test, 'path-to', 'my', 'keys')['test2'] = 4
print(test)
print(make_path(test)) # It's okay even no paths passed
Вывод:
{'path-to': {'test': 1}}
{'path-to': {'test': 1, 'my': {'keys': {'test2': 4}}}}
{'path-to': {'test': 1, 'my': {'keys': {'test2': 4}}}}
Решение 4. Усовершенствовано из решения 2: Создайте собственный класс
class MyDefaultDict(dict):
def __missing__(self, key):
self[key] = MyDefaultDict()
return self[key]
my_dict = MyDefaultDict()
print(my_dict)
my_dict['path-to']['my']['keys'] = 'hello'
print(my_dict)
вывод:
{}
{'path-to': {'my': {'keys': 'hello'}}}
Вывод
Я думаю, что решение 3 является больше всего соответствует вашим потребностям, но вы можете использовать любые другие варианты, если это соответствует вашему случаю.
Append
Как насчет решения 4, мы уже задали: d уже разобрали с json? Ваше решение начинается с типа MyDefaultDict (), а не с того, который возвращается из jsons.loads ()
Если вы можете редактировать json.loads
деталь, попробуйте:
import json
class MyDefaultDict(dict):
def __missing__(self, key):
self[key] = MyDefaultDict()
return self[key]
data = '{"path-to": {"my": {"keys": "hello"}}}'
my_dict = json.loads(data, object_pairs_hook=MyDefaultDict)
print(type(my_dict))
output:
<class '__main__.MyDefaultDict'>