How to get nested dictionary key value with .get()
Asked Answered
U

6

28

With a simple dictionary like:

myDict = {'key1':1, 'key2':2}

I can safely use:

print myDict.get('key3')

and even while 'key3' is not existent no errors will be thrown since .get() still returns None.

Now how would I achieve the same simplicity with a nested keys dictionary:

myDict={}
myDict['key1'] = {'attr1':1,'attr2':2}

The following will give a KeyError:

print myDict.get('key1')['attr3']

This will go through:

print myDict.get('key1').get('attr3')

but it will fail with adn AttributeError: 'NoneType' object has no attribute 'get':

print myDict.get('key3').get('attr1')
Usual answered 5/5, 2014 at 1:50 Comment(1)
See also: stackoverflow.com/questions/2352181/…Lubricity
C
50

dict.get accepts additional default parameter. The value is returned instead of None if there's no such key.

print myDict.get('key1', {}).get('attr3')
Collencollenchyma answered 5/5, 2014 at 1:53 Comment(5)
See also: stackoverflow.com/questions/2352181/…Lubricity
Note that myDict.get('key1', {}) can still return None if myDict['key1'] = None is set explicitly. I would actually recommend this approach.Reform
@PavelVergeev, My answer, and the other answer you linked both will raise TypeError: 'NoneType' object has no attribute '__getitem__' in such case. ;)Collencollenchyma
what can be passed on the empty curly braces ? what is this for ? thanksManatarms
@Gel, {} in python is a dictionary (hash map) literal. It's used as a fallback value in case of there's no 'key1' entry in myDict.Collencollenchyma
M
8

There is a very nice blog post from Dan O'Huiginn on the topic of nested dictionaries. He ultimately suggest subclassing dict with a class that handles nesting better. Here is the subclass modified to handle your case trying to access keys of non-dict values:

class ndict(dict):
     def __getitem__(self, key):
         if key in self: return self.get(key)
         return self.setdefault(key, ndict())

You can reference nested existing keys or ones that don't exist. You can safely use the bracket notation for access rather than .get(). If a key doesn't exist on a NestedDict object, you will get back an empty NestedDict object. The initialization is a little wordy, but if you need the functionality, it could work out for you. Here are some examples:

In [97]: x = ndict({'key1': ndict({'attr1':1, 'attr2':2})})

In [98]: x
Out[98]: {'key1': {'attr1': 1, 'attr2': 2}}

In [99]: x['key1']
Out[99]: {'attr1': 1, 'attr2': 2}

In [100]: x['key1']['key2']
Out[100]: {}

In [101]: x['key2']['key2']
Out[101]: {}

In [102]: x['key1']['attr1']
Out[102]: 1
Magnifico answered 5/5, 2014 at 3:34 Comment(0)
S
6

Use exceptions:

try:
    print myDict['key1']['attr3']
except KeyError:
    print "Can't find my keys"
Snakebite answered 5/5, 2014 at 1:54 Comment(1)
Now why the hell couldn't I have thought of that?!?Strawberry
U
0

That's normal since key3 doesn't exist so

myDict.get('key3')

returns none..

NoneType object has no attribute..

So you have to store the value of myDict.get('key3'), test if it's not null and then use the get method on the stored item

Unstable answered 5/5, 2014 at 1:56 Comment(0)
M
0

NestedDict allows you to handle nested dictionaries with the same interface of a standard dictionary.

from ndicts.ndicts import NestedDict

my_dict = {'key1': {'attr1': 1,'attr2': 2}
nd = NestedDict(my_dict)
>>> nd.get(("key1", "attr3"), "not found")
'not found'
>>> nd.get(("key3", "attr1"), "not found")
'not found'

To install ndicts

pip install ndicts
Mislike answered 8/3, 2022 at 17:23 Comment(0)
A
0

I improve the solution proposed by jxstandford to handle list in dict.

class NestedDict(dict):

    def __getitem__(self, key):
        if key in self:
            return self.to_nested(self.get(key))
        return self.setdefault(key, NestedDict())


    @staticmethod
    def to_nested(obj: Any) -> Any:
        if not obj:
            return NestedDict()
        if isinstance(obj, dict):
            return NestedDict(obj)
        if isinstance(obj, list):
            return list(map(NestedDict.to_nested, obj))
        return obj

So it can handle dict like that :

foo = {"bar": [{"a:":3}]}
{} == foo["bar"][0]["b"]
Apomorphine answered 3/3, 2023 at 9:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.