Как преобразовать dict в рекурсивный defaultdict и загрузить JSON? - PullRequest
0 голосов
/ 07 июня 2018

Есть ли способ загрузить JSON-код в рекурсивный defaultdict, чтобы избежать KeyError, используя Python 2.7?

Например:

from __future__ import print_function
from collections import defaultdict
import json

S =  '{"a": [{"b": "TEST1", "p": "TEST2"}, {"b": "TEST3", "p": "TEST4"}]}'

d = json.loads(S)
nd = lambda: defaultdict(nd)
ni = nd()
print('1: ', ni['a'][0]['b'])
ni.update(d)
print('2: ', ni['a'][0]['b'])
print('3: ', ni['a'][1]['p'])
print('4: ', ni['a'][1]['c'])

Результат

1:  defaultdict(<function <lambda> at 0x0266F530>, {})
2:  TEST1
3:  TEST4
Traceback (most recent call last):
  File "C:/...", line 16, in <module>
    print('4: ', ni['a'][1]['c'])
KeyError: 'c'

Похоже, что после ni.update(d) ni работает как dict, а не как рекурсивный defaultdict.Есть ли способ добавить dict в рекурсив defaultdict и сохранить его свойства?

Я ожидаю, что результат на шаге 4 похож на следующий:

4:  defaultdict(<function <lambda> at 0x0266F530>, {})

1 Ответ

0 голосов
/ 07 июня 2018

Недостаточно создать рекурсивный диктант.Вы должны рекурсивно загрузить объект JSON в ваш диктовку.

В вашем коде происходит то, что ni['a'] - это нормальный диктат, а не диктат типа nd.Когда вы запускаете ni.update(d), обновление не достаточно умен, чтобы пройти d, записывая объекты на каждом уровне в объекты аналогичного типа.Вместо этого он просто копирует значения первого уровня и ключи d в ni.Значения первого уровня - это просто обычные диктовки или что-то в этом роде.

Чтобы правильно инициализировать ni, вам нужно написать рекурсивную функцию, которая определяет, является ли каждое значение диктом, массивом или скаляром.Если это диктат, он должен вызвать nd, а затем заполнить результат значениями, для которых он будет действовать таким же рекурсивным способом.

ИЛИ, вы можете использовать аргумент object_hook - json.loads.Подробнее см. https://docs.python.org/2/library/json.html#json.load.Какую бы функцию вы здесь ни передали, она будет вызываться для каждого dict, созданного на любом уровне анализа.Так что функция

def defaultdict_from_dict(d):
    nd = lambda: defaultdict(nd)
    ni = nd()
    ni.update(d)
    return ni

или что-то подобное, вероятно, подойдет вам.

...