2012-07-28 20 views
8

Tengo un diccionario que contiene diccionarios, que también pueden contener diccionarios, p. Ej.Python: acceso a los valores anidados en los diccionarios

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

Actualmente estoy desembalaje para obtener el 'proyecto de ley para' ID 001, a1 'Transacción Ref' 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 evitar pensar que esto es es un poco de torpe, especialmente los últimos dos líneas - me siento como algo en la línea de lo siguiente debería funcionar:

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

¿hay un método más sencillo para la perforación hacia abajo en los diccionarios anidados sin tener que descomprimir en inter im variables?

+6

La línea que siente debe trabajar realmente lo hace. –

Respuesta

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

en realidad funciona. transactions['Transaction Details'] es una expresión que denota un dict, por lo que puede buscar en él. Sin embargo, para los programas prácticos, preferiría un enfoque de OO a los dictados anidados. 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 algunos entornos, es posible que desee ponerse KeyError al hacer búsquedas, y en este contexto, que trabaja demasiado, es difícil saber qué diccionario está fallando la búsqueda:

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 
+0

Increíblemente útil, muchas gracias! – user1530213

20

Se puede utilizar 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, sólo puede pasar en una lista como esta:

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

Espero que no te importe, agregué una edición para aclarar la verdadera capacidad de búsqueda dinámica de esta función. La capacidad de pasar una lista de claves de búsqueda sobre la marcha hace que este sea un corte por encima de las otras técnicas. –

2

siguiente es otro modo de acceder a los diccionarios anidados

>>> 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í, 'nombre' variable se refiere a 'dbo [' m '] [' d '] [' v '] [' versión '] ', que parece mucho más corto y ordenado.

Este método no lanzará KeyError. Si no se encuentra una clave, obtendrá 'Ninguno'.

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

+0

Lanzará un TypeError si intentas name = 'm__foo__v__foo': TypeError: el descriptor 'get' requiere un objeto 'dict' pero recibió un 'NoneType' – krasnaya

Cuestiones relacionadas