Funciones que ayudan a entender la estructura de json (dict).

No he encontrado hay una manera de hacer esto. Digamos que recibo un objeto JSON como este:

{'1_data':{'4_data':[{'5_data':'hooray'}, {'3_data':'hooray2'}], '2_data':[]}} 

Es difícil decir al instante, ¿cómo debo obtener el valor de la clave 3_data : data['1_data']['4_data'][1]['3_data']

Sé de pprint , ayuda a entender un poco la estructura. Pero a veces los datos son enormes, y lleva tiempo.

¿Hay algún método que pueda ayudarme con eso?

Aquí hay una familia de generadores recursivos que se pueden usar para buscar a través de un objeto compuesto de listas y dictados. find_key produce una tupla que contiene una lista de las claves del diccionario y los índices de la lista que conducen a la clave que usted pasa; La tupla también contiene el valor asociado con esa clave. Como es un generador, encontrará todas las claves coincidentes si el objeto contiene varias claves coincidentes, si lo desea.

 def find_key(obj, key): if isinstance(obj, dict): yield from iter_dict(obj, key, []) elif isinstance(obj, list): yield from iter_list(obj, key, []) def iter_dict(d, key, indices): for k, v in d.items(): if k == key: yield indices + [k], v if isinstance(v, dict): yield from iter_dict(v, key, indices + [k]) elif isinstance(v, list): yield from iter_list(v, key, indices + [k]) def iter_list(seq, key, indices): for k, v in enumerate(seq): if isinstance(v, dict): yield from iter_dict(v, key, indices + [k]) elif isinstance(v, list): yield from iter_list(v, key, indices + [k]) # test data = { '1_data': { '4_data': [ {'5_data': 'hooray'}, {'3_data': 'hooray2'} ], '2_data': [] } } for t in find_key(data, '3_data'): print(t) 

salida

 (['1_data', '4_data', 1, '3_data'], 'hooray2') 

Para obtener una sola lista de teclas, puede pasar find_key a la next función. Y si desea usar una lista de claves para obtener el valor asociado, puede usar un simple bucle for .

 seq, val = next(find_key(data, '3_data')) print('seq:', seq, 'val:', val) obj = data for k in seq: obj = obj[k] print('obj:', obj, obj == val) 

salida

 seq: ['1_data', '4_data', 1, '3_data'] val: hooray2 obj: hooray2 True 

Si la clave puede faltar, a continuación proporcione una tupla predeterminada apropiada. P.ej:

 seq, val = next(find_key(data, '6_data'), ([], None)) print('seq:', seq, 'val:', val) if seq: obj = data for k in seq: obj = obj[k] print('obj:', obj, obj == val) 

salida

 seq: [] val: None 

Tenga en cuenta que este código es para Python 3. Para ejecutarlo en Python 2 debe reemplazar todo el yield from declaraciones, por ejemplo, reemplazar

 yield from iter_dict(obj, key, []) 

con

 for u in iter_dict(obj, key, []): yield u 

Cómo funciona

Para comprender cómo funciona este código, debe estar familiarizado con la recursión y con los generadores de Python. También puede encontrar útil esta página: Cómo entender los generadores en Python ; También hay varios tutoriales de generadores de Python disponibles en línea.

El objeto Python devuelto por json.load o json.loads es generalmente un dict, pero también puede ser una lista. Pasamos ese objeto al generador find_key como obj arg, junto con la cadena de key que queremos ubicar. find_key continuación, find_key llama a iter_dict o iter_list , según corresponda, y les pasa el objeto, la clave y una lista vacía, que se utiliza para recostackr las claves dict y la lista de índices que conducen a la clave que deseamos.

iter_dict itera sobre cada par (k, v) en el nivel superior de su d dict arg. Si k coincide con la clave que estamos buscando, la lista de indices actual se muestra con k adjunta, junto con el valor asociado. Debido a que iter_dict es recursivo, los iter_dict (lista de índices, valor) pasan al nivel anterior de recursión, y eventualmente ascienden a find_key y luego al código que se llama find_key . Tenga en cuenta que este es el “caso base” de nuestra recursión: es la parte del código que determina si esta ruta de recursión conduce a la clave que queremos. Si una ruta de recursión nunca encuentra una clave que coincida con la clave que estamos buscando, entonces la ruta de recursión no agregará nada a los indices y terminará sin ceder nada.

Si la v actual es un dict, entonces necesitamos examinar todos los pares (clave, valor) que contiene. Lo hacemos haciendo una llamada recursiva a iter_dict , pasando que v es su objeto de inicio y la lista de indices actual. Si la v actual es una lista, en su lugar la llamamos iter_list , pasándole los mismos argumentos.

iter_list funciona de manera similar a iter_dict excepto que una lista no tiene ninguna clave, solo contiene valores, por lo que no realizamos la prueba de la k == key , solo realizamos cualquier dictado o lista que contenga la lista original.

El resultado final de este proceso es que cuando find_key sobre find_key obtenemos pares de (índices, valor) donde cada lista de indices es la secuencia de teclas dict y listas de índices que terminan con éxito en un elemento dict con nuestra tecla deseada, y el value es el valor asociado con esa clave en particular.

Si desea ver otros ejemplos de este código en uso, consulte cómo modificar la clave de un Json nested y Cómo puedo seleccionar una clave profundamente anidada: valores del diccionario en Python .

También eche un vistazo a mi nueva función show_indices más optimizada.