Возвращает список всех имен переменных в вложенном документе python dict / json в точечной нотации

Я ищу функцию, которая работает на произвольно вложенном dict / array на языке python в формате JSON-esque и возвращает список строк, в которых хранятся все имена переменных, которые он содержит, до бесконечной глубины. Итак, если объект …

x = { 'a': 'meow', 'b': { 'c': 'asd' }, 'd': [ { "e": "stuff", "f": 1 }, { "e": "more stuff", "f": 2 } ] } 

mylist = f(x) вернется …

 >>> mylist ['a', 'b', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f'] 

  • Python: обрабатывать JSON Decode Error, когда ничего не возвращается
  • UnicodeDecodeError при использовании json.dumps ()
  • UnicodeDecodeError: кодек 'utf8' не может декодировать байт 0xa5 в позиции 0: недопустимый стартовый байт
  • Django JSONField внутри ArrayField
  • Вставить текст в PNG
  • Как преобразовать список в jsonarray в python
  • Загрузка Python UTF-8 JSON
  • Могу ли я использовать данные JSON для добавления новых объектов в Django?
  • 4 Solutions collect form web for “Возвращает список всех имен переменных в вложенном документе python dict / json в точечной нотации”

     def dot_notation(obj, prefix=''): if isinstance(obj, dict): if prefix: prefix += '.' for k, v in obj.items(): for res in dot_notation(v, prefix+str(k)): yield res elif isinstance(obj, list): for i, v in enumerate(obj): for res in dot_notation(v, prefix+'['+str(i)+']'): yield res else: yield prefix 

    Пример:

     >>> list(dot_notation(x)) ['a', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f'] 

    Это весело. Я решил это, используя рекурсию.

     def parse(d): return parse_dict(d) def parse_dict(d): items = [] for key, val in d.iteritems(): if isinstance(val, dict): # use dot notation for dicts items += ['{}.{}'.format(key, vals) for vals in parse_dict(val)] elif isinstance(val, list): # use bracket notation for lists items += ['{}{}'.format(key, vals) for vals in parse_list(val)] else: # just use the key for everything else items.append(key) return items def parse_list(l): items = [] for idx, val in enumerate(l): if isinstance(val, dict): items += ['[{}].{}'.format(idx, vals) for vals in parse_dict(val)] elif isinstance(val, list): items += ['[{}]{}'.format(idx, vals) for vals in parse_list(val)] else: items.append('[{}]'.format(val)) return items 

    Вот мой результат:

     >>> parse(x) ['a', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f'] 

    РЕДАКТИРОВАТЬ

    Здесь он снова использует генераторы, потому что мне понравился ответ Fj

     def parse(d): return list(parse_dict(d)) def parse_dict(d): for key, val in d.iteritems(): if isinstance(val, dict): # use dot notation for dicts for item in parse_dict(val): yield '{}.{}'.format(key, item) elif isinstance(val, list): # use bracket notation for item in parse_list(val): yield '{}{}'.format(key, item) else: # lowest level - just use the key yield key def parse_list(l): for idx, val in enumerate(l): if isinstance(val, dict): for item in parse_dict(val): yield '[{}].{}'.format(idx, item) elif isinstance(val, list): for item in parse_list(val): yield '[{}]{}'.format(idx, item) else: yield '[{}]'.format(val) 

    Тот же результат:

     >>> parse(x) ['a', 'b.c', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f'] 

    Если верхний уровень вашего объекта может быть списком (массив, в терминологии JSON), ваш выходной формат не работает: например, ["foo", "bar"] вы логически возвращаете ['[0]', '[1]'] , что, вероятно, не то, что вы хотите. Вы можете решить это, передав также имя объекта небольшой модификации ответа FJ:

     def paths(container, name): if isinstance(container, list): for i, element in enumerate(container): for path in paths(element, "%s[%d]" % (name, i)): yield path elif isinstance(container, dict): for k, element in container.items(): for path in paths(element, "%s.%s" % (name, k)): yield path else: yield name 

    Применение:

     >>> list(paths(x, "x")) ['x.a', 'xbc', 'xd[0].e', 'xd[0].f', 'xd[1].e', 'xd[1].f'] >>> list(paths(["foo", "bar"], "array")) ['array[0]', 'array[1]'] 

    Python 3.3 представляет yield from синтаксиса, который делает это немного чище:

     def paths(container, name): if isinstance(container, list): for i, element in enumerate(container): yield from paths(element, "%s[%d]" % (name, i)) elif isinstance(container, dict): for k, element in container.items(): yield from paths(element, "%s.%s" % (name, k)) else: yield name 

    Только Python 3.3+:

     def f(x, parent=''): if isinstance(x, dict): if parent: parent += '.' for key in x: yield parent + key yield from f(x[key], parent + key) elif isinstance(x, list): for idx, subx in enumerate(x): yield from f(subx, '{}[{}]'.format(parent, idx)) 

    Python 2.x ~ Python 3.2

     def f(x, parent=''): if isinstance(x, dict): if parent: parent += '.' for key in x: yield parent + key for y in f(x[key], parent + key): yield y elif isinstance(x, list): for idx, subx in enumerate(x): for y in f(subx, '{}[{}]'.format(parent, idx)): yield y 

     >>> x = {'a': 'meow', 'b': {'c': 'asd'}, 'd':[{"e":"stuff","f":1}, {"e":"more stuff","f":2}]} >>> list(f(x)) ['d', 'd[0].e', 'd[0].f', 'd[1].e', 'd[1].f', 'a', 'b', 'b.c'] 
    Python - лучший язык программирования в мире.