Python – acceso a valores nesteds dentro de diccionarios

Tengo un diccionario que contiene diccionarios, que también pueden contener diccionarios, por ejemplo,

dictionary = {'ID': 0001, 'Name': 'made up name', 'Transactions': {'Transaction Ref': 'a1', 'Transaction Details': {'Bill To': 'abc', 'Ship To': 'def', 'Product': 'Widget A' ...} ...} ... } 

Actualmente estoy desempaquetando para obtener la ‘Factura a’ para la ID 001, ‘Referencia de transacción’ a1 de la siguiente manera:

 if dictionary['ID'] == 001: transactions = dictionary['Transactions'] if transactions['Transaction Ref'] == 'a1': transaction_details = transactions['Transaction Details'] bill_to = transaction_details['Bill To'] 

No puedo dejar de pensar que esto es un poco torpe, especialmente en las dos últimas líneas. Siento que algo similar a lo siguiente debería funcionar:

 bill_to = transactions['Transaction Details']['Bill To'] 

¿Existe un enfoque más sencillo para profundizar en diccionarios nesteds sin tener que descomprimir en variables interinas?

 bill_to = transactions['Transaction Details']['Bill To'] 

realmente funciona transactions['Transaction Details'] es una expresión que denota un dict , por lo que puede hacer una búsqueda en ella. Sin embargo, para los progtwigs prácticos, preferiría un enfoque OO a los dictados nesteds. collections.namedtuple es particularmente útil para configurar rápidamente un grupo de clases que solo contienen datos (y ningún comportamiento propio).

Hay una advertencia: en algunas configuraciones, es posible que desee detectar KeyError al realizar búsquedas, y en esta configuración también funciona, es difícil saber qué búsqueda de diccionario falló:

 try: bill_to = transactions['Transaction Details']['Bill To'] except KeyError: # which of the two lookups failed? # we don't know unless we inspect the exception; # but it's easier to do the lookup and error handling in two steps 

Puedes usar algo como esto:

 >>> def lookup(dic, key, *keys): ... if keys: ... return lookup(dic.get(key, {}), *keys) ... return dic.get(key) ... >>> d = {'a':{'b':{'c':5}}} >>> print lookup(d, 'a', 'b', 'c') 5 >>> print lookup(d, 'a', 'c') None 

Además, si no desea definir sus claves de búsqueda como parámetros individuales, simplemente puede pasarlas como una lista como esta:

 >>> print lookup(d, *['a', 'b', 'c']) 5 >>> print lookup(d, *['a', 'c']) None 

A continuación se presenta otra forma de acceder a diccionarios nesteds.

 >>> dbo={'m':{'d':{'v':{'version':1}}}} >>> name='m__d__v__version' # it'll refer to 'dbo['m']['d']['v']['version']', '__' is the separator >>> version = reduce(dict.get, name.split('__'), dbo) >>> print version 1 >>> 

Aquí, la variable ‘nombre’ se refiere a ‘dbo [‘ m ‘] [‘ d ‘] [‘ v ‘] [‘ version ‘]’, que parece mucho más corto y ordenado.

Este método no lanzará KeyError. Si no se encuentra una clave, obtendrás ‘Ninguna’.

Ref .: http://code.activestate.com/recipes/475156-using-reduce-to-access-deeply-nested-dictionaries/