Элегантный способ установить значения во вложенном json в python

Я устанавливаю некоторые значения во вложенном JSON. В JSON не обязательно, чтобы ключи присутствовали всегда.
Мой пример кода выглядит следующим образом.

if 'key' not in data:
    data['key'] = {}
if 'nested_key' not in data['key']:
    data['key']['nested_key'] = some_value

Есть ли другой элегантный способ добиться этого? Простое присвоение значения без if's вроде - data['key']['nested_key'] = some_value иногда может выдать KeyError.

Я ссылался на несколько похожих вопросов о «получении вложенного JSON» в StackOverflow, но ни один из них не соответствовал моему требованию. Поэтому я добавил новый вопрос. В случае, если это повторяющийся вопрос, я удалю его, как только направлюсь к правильному вопросу.

Спасибо


person Manthan Jamdagni    schedule 06.02.2019    source источник
comment
В случае со словарем Python для получения значения ключа нам нужна проверка ключа. Но для присвоения значения ключу, даже если ключ отсутствует, будет создан новый ключ.   -  person bumblebee    schedule 06.02.2019
comment
да, но в моем случае есть вложенные ключи, которые приводят к KeyError, если оба отсутствуют.   -  person Manthan Jamdagni    schedule 06.02.2019


Ответы (2)


Обратите внимание, что для вставки вам не нужно проверять наличие ключа, и вы можете добавить его напрямую. Но можно использовать defaultdict. Это особенно полезно для таких значений, как списки.

from collections import defaultdict

data = defaultdict(dict)
data['key']['nested_key'] = some_value

defaultdict гарантирует, что вы никогда не получите ключевую ошибку. Если ключ не существует, он возвращает пустой объект того типа, которым вы его инициализировали.

Пример на основе списка:

from collections import defaultdict

data = defaultdict(list)
data['key'].append(1)

что в противном случае нужно будет сделать, как показано ниже:

data = {}
if 'key' not in data:
    data['key'] = ['1']
else:
    data['key'].append('2')

Пример на основе существующего dict:

from collections import defaultdict

data = {'key1': 'sample'}    
data_new = defaultdict(dict,data)    
data_new['key']['something'] = 'nothing'

print data_new

Выход:

defaultdict(<type 'dict'>, {'key1': 'sample', 'key': {'something': 'nothing'}})
person Jay    schedule 06.02.2019
comment
Первый аргумент defaultdict должен быть callable или None, верно? Также, когда я пытаюсь использовать defaultdict с вложенным dict, он все равно выдает мне KeyError from collections import defaultdict data = {} dic = defaultdict(None, data) dic['something']['new'] = 'hello' KeyError: 'something' - person Manthan Jamdagni; 06.02.2019
comment
@ManthanJamdagni, пожалуйста, проверьте мой обновленный ответ. Он не выдает ошибку для вложенных диктов. Используйте его так, как это сделал я. - person Jay; 06.02.2019
comment
Привет, @Jay, возможно, я не очень четко сформулировал вопрос, но у меня уже был словарь, который мне пришлось превратить в словарь по умолчанию, чтобы добиться того, что я искал. Так что для меня код будет - data1 = defaultdict(dict, data) . Спасибо, в любом случае. - person Manthan Jamdagni; 06.02.2019
comment
@ManthanJamdagni, извините, я неправильно понял. Ты прав. Ваш код будет data1 = defaultdict(dict, data). Я также обновил свой ответ. - person Jay; 06.02.2019

Вы можете написать в одном заявлении:

data.setdefault('key', {})['nested_value'] = some_value

но я не уверен, что это выглядит более элегантно.

PS: если вы предпочитаете использовать defaultdict, предложенный Джеем, вы можете инициализировать новый dict исходным, возвращенным json.loads(), а затем передать его json.dumps():

data2 = defaultdict(dict, data)
data2['key'] = value
json.dumps(data2)    # print the expected dict
person rene-d    schedule 06.02.2019