10 votes

Accès aux valeurs imbriquées dans les dictionnaires

Je dispose d'un dictionnaire qui contient des dictionnaires, qui peuvent également contenir des dictionnaires, par ex.

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

Actuellement, je décompresse pour obtenir le "Bill To" pour ID 001, "Transaction Ref" a1 comme suit :

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

Je ne peux m'empêcher de penser que c'est un peu maladroit, surtout les deux dernières lignes - j'ai l'impression que quelque chose du genre de ce qui suit devrait fonctionner :

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

Existe-t-il une approche plus simple pour descendre dans les dictionnaires imbriqués sans avoir à déballer dans des variables intermédiaires ?

20voto

astynax Points 1436

Vous pouvez utiliser quelque chose comme ça :

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

En outre, si vous ne souhaitez pas définir vos clés de recherche en tant que paramètres individuels, vous pouvez simplement les transmettre sous forme de liste, comme ceci :

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

16voto

larsmans Points 167484
bill_to = transactions['Transaction Details']['Bill To']

fonctionne réellement. transactions['Transaction Details'] est une expression désignant une dict Vous pouvez donc y faire des recherches. Pour les programmes pratiques, je préférerais une approche OO des dicts imbriquées, cependant. collections.namedtuple est particulièrement utile pour mettre en place rapidement un ensemble de classes qui ne contiennent que des données (et aucun comportement propre).

Il y a une mise en garde : dans certains cas, vous pourriez vouloir attraper KeyError lors des recherches, et dans cette configuration, cela fonctionne aussi, il est difficile de dire quelle recherche de dictionnaire a échoué :

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

2voto

blackfyre Points 2399

Voici une autre façon d'accéder aux dictionnaires imbriqués

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

Ici, la variable "name" fait référence à "dbo['m']['d']['v']['version']", ce qui semble beaucoup plus court et plus clair.

Cette méthode n'entraînera pas de KeyError. Si une clé n'est pas trouvée, vous obtiendrez 'None'.

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

0voto

edd313 Points 33

Vous pouvez accéder aux dictionnaires imbriqués avec un tuple en utilisant NestedDict .

>>> from ndicts.ndicts import NestedDict
>>> nested_dict = {"a": {"a": 0, "b": 1},
...                "b": {"a": 2, "b": 3}}
>>> nd = NestedDict(nested_dict)
>>> nd["a", "a"]
0
>>> nd["b", "a"]
2
>>> nd["a"]
{"a": 0, "b": 1}

Pour installer ndicts :

pip install ndicts

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X