45

I am new to python and need help in solving an issue:

I have a dictionary like

tmpDict = {'ONE':{'TWO':{'THREE':10}}}

Do we have any other way to access THREE's value other than doing

tmpDict['ONE']['TWO']['THREE']

?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Gana
  • 979
  • 3
  • 10
  • 18

5 Answers5

39

As always in python, there are of course several ways to do it, but there is one obvious way to do it.

tmpdict["ONE"]["TWO"]["THREE"] is the obvious way to do it.

When that does not fit well with your algorithm, that may be a hint that your structure is not the best for the problem.

If you just want to just save you repetative typing, you can of course alias a subset of the dict:

>>> two_dict = tmpdict['ONE']['TWO'] # now you can just write two_dict for tmpdict['ONE']['TWO']
>>> two_dict["spam"] = 23
>>> tmpdict
{'ONE': {'TWO': {'THREE': 10, 'spam': 23}}}
ch3ka
  • 11,792
  • 4
  • 31
  • 28
  • 2
    True, accessing a dict's element through the `[]` operator is an obvious way. But I highly recommend to read also [this answer](https://stackoverflow.com/a/52260663/3388962) to a related question. There are realistic scenarios where one has to pass a "path" (possibly of variable length) to an element in a (possibly deeply) nested dictionary where it would be cumbersome to call `get()` or the `[]` operator on every intermediate dict. – normanius Dec 05 '18 at 15:19
  • You however can't alias an alias, so if you are planning to do the process more than once in a recursive manner, you gotta have the keys, or else it's gonna pass by value the second time. – Ren Feb 21 '20 at 23:05
20

My implementation:

def get_nested(data, *args):
    if args and data:
        element  = args[0]
        if element:
            value = data.get(element)
            return value if len(args) == 1 else get_nested(value, *args[1:])

Example usage:

>>> dct={"foo":{"bar":{"one":1, "two":2}, "misc":[1,2,3]}, "foo2":123}
>>> get_nested(dct, "foo", "bar", "one")
1
>>> get_nested(dct, "foo", "bar", "two")
2
>>> get_nested(dct, "foo", "misc")
[1, 2, 3]
>>> get_nested(dct, "foo", "missing")
>>>

There are no exceptions raised in case a key is missing, None value is returned in that case.

grafi71
  • 379
  • 2
  • 5
15

You can use the get() on each dict. Make sure that you have added the None check for each access.

Siva Arunachalam
  • 7,582
  • 15
  • 79
  • 132
  • .get is not made for checking afterwards if the returned value is `None`, you could also just check if the key is in the dictionary: `key in dict` or for older versions `dict.has_key` – dav1d May 01 '12 at 15:15
  • 15
    `tmpDict.get('ONE', {}).get('TWO', {}).get('THREE')` by using get with empty dict as default... if any of the three keys doesn't exist, it will returns `None` – akhy Aug 25 '16 at 02:41
  • @dav1d why do you say that .get is not made for checking afterwards is the returned value is None? Why else would this method exist? – Peter Schorn Mar 18 '20 at 10:05
5

The answer was given already by either Sivasubramaniam Arunachalam or ch3ka.

I am just adding a performances view of the answer.

dicttest={}
dicttest['ligne1']={'ligne1.1':'test','ligne1.2':'test8'}
%timeit dicttest['ligne1']['ligne1.1']
%timeit dicttest.get('ligne1').get('ligne1.1')

gives us :

112 ns ± 29.7 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

235 ns ± 9.82 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Community
  • 1
  • 1
Mayeul sgc
  • 1,964
  • 3
  • 20
  • 35
3

No, those are nested dictionaries, so that is the only real way (you could use get() but it's the same thing in essence). However, there is an alternative. Instead of having nested dictionaries, you can use a tuple as a key instead:

tempDict = {("ONE", "TWO", "THREE"): 10}
tempDict["ONE", "TWO", "THREE"]

This does have a disadvantage, there is no (easy and fast) way of getting all of the elements of "TWO" for example, but if that doesn't matter, this could be a good solution.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • 3
    I'm not quite clear on how this would be beneficial in any practical application. If your data is structured, flattening it and upping the key complexity doesn't really seem to add value. – Silas Ray May 01 '12 at 15:10
  • 2
    @sr2222 It means you don't have to have a large number of dicts, it means you don't have to worry about creating the sub-dictionaries when adding new values, and it could be more natural depending on the application. I think that's enough to be worthwhile in some situations. – Gareth Latty May 01 '12 at 15:15