10

I have a dictionary which contains dictionaries, which may also contain dictionaries, e.g.

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

Currently I'm unpacking to get the 'Bill To' for ID 001, 'Transaction Ref' a1 as follows:

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

I can't help but think this is is a little clunky, especially the last two lines - I feel like something along the lines of the following should work:

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

Is there a simpler approach for drilling down into nested dictionaries without having to unpack into interim variables?

2
  • 7
    The line you feel should work actually does. Commented Jul 28, 2012 at 11:57
  • 1
    Note that 0001 is not valid in Python3, neither is any number with leading zeroes. Commented Aug 6, 2019 at 2:00

4 Answers 4

20

You can use something like this:

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

Additionally, if you don't want to define your search keys as individual parameters, you can just pass them in as a list like this:

>>> print lookup(d, *['a', 'b', 'c'])
5
>>> print lookup(d, *['a', 'c'])
None
Sign up to request clarification or add additional context in comments.

1 Comment

I hope you don't mind, I added an edit to clarify the true dynamic search capability of this function. The ability to pass in a list of search keys on-the-fly makes this a cut above the other techniques.
16
bill_to = transactions['Transaction Details']['Bill To']

actually works. transactions['Transaction Details'] is an expression denoting a dict, so you can do lookup in it. For practical programs, I would prefer an OO approach to nested dicts, though. collections.namedtuple is particularly useful for quickly setting up a bunch of classes that only contain data (and no behavior of their own).

There's one caveat: in some settings, you might want to catch KeyError when doing lookups, and in this setting, that works too, it's hard to tell which dictionary lookup failed:

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

Comments

2

Following is another way of accessing nested dictionaries

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

Here, variable 'name' refers to 'dbo['m']['d']['v']['version']', which seems much shorter and neat.

This method will not throw KeyError. If a key is not found then you'll get 'None'.

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

1 Comment

It will throw a TypeError if you try name='m__foo__v__foo': TypeError: descriptor 'get' requires a 'dict' object but received a 'NoneType'
0

You can access nested dictionaries with a tuple using 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}

To install ndicts:

pip install ndicts

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.