3

I have several nested dictionaries within lists, and I need to verify if a specific path exist e.g.

dict1['layer1']['layer2'][0]['layer3']

How can I check with an IF statement if the path is valid?

I was thinking to

if dict1['layer1']['layer2'][0]['layer3'] :

but it doesn't work

Luigi T.
  • 506
  • 3
  • 11
  • 22
  • 2
    One way would be to [ask for forgiveness](http://stackoverflow.com/questions/12265451/ask-forgiveness-not-permission-explain) rather than testing for its existence. – roganjosh Apr 17 '17 at 19:54
  • So, you `try` to follow that path and assume it always exists, `except` when it doesn't. – ForceBru Apr 17 '17 at 19:55
  • I try to assign the value in the path in a variable, but it fails returning an error (KeyError: 'media' ) – Luigi T. Apr 17 '17 at 21:11

6 Answers6

5

Here's the explicit short code with try/except:

try:
    dict1['layer1']['layer2'][0]['layer3']
except KeyError:
    present = False
else:
    present = True

if present: 
    ...

To get the element:

try:
    obj = dict1['layer1']['layer2'][0]['layer3']
except KeyError:
    obj = None  # or whatever
Kirill Bulygin
  • 3,658
  • 1
  • 17
  • 23
2

I wanted to propose another solution, because I've been thinking about it too.

if not dict1.get("layer1", {}).get("layer2", {})[0].get("layer3", {}):
    ...

dict.get() attempts to get the key at each stage. If the key is not present, an empty dict will be returned, instead of the nested dict (this is needed, because trying to call .get() on the default return of None will yield an AttributeError). If the return is empty, it will evaluate to false. So, this wouldn't work if the final result was an empty dict anyway, but if you can guarantee the results will be filled, this is an alternative that is fairly simple.

rorance_
  • 349
  • 1
  • 10
1

If you don't want to go the try/except route, you could whip up a quick method to do this:

def check_dict_path(d, *indices):
    sentinel = object()
    for index in indices:
        d = d.get(index, sentinel)
        if d is sentinel:
            return False
    return True


test_dict = {1: {'blah': {'blob': 4}}}

print check_dict_path(test_dict, 1, 'blah', 'blob') # True
print check_dict_path(test_dict, 1, 'blah', 'rob') # False

This might be redundant if you're also trying to retrieve the object at that location (rather than just verify whether the location exists). If that's the case, the above method can easily be updated accordingly.

Jared Goguen
  • 8,772
  • 2
  • 18
  • 36
0

As far as I know, you've to go step by step, i.e.:

if 'layer1' in dict1:
   if 'layer2' in dict1['layer1']

ans so on...

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
0

Here is a similar question with the answer I would recommend:

Elegant way to check if a nested key exists in a python dict

Alexander
  • 7,484
  • 4
  • 51
  • 65
0

Using recursive function:

def path_exists(path, dict_obj, index = 0):
    if (type(dict_obj) is dict and path[index] in dict_obj.keys()):
        if (len(path) > (index+1)):
            return path_exists(path, dict_obj[path[index]], index + 1)
        else:
            return True
    else:
        return False

Where path is a list of strings representing the nested keys.