1

I'm trying to navigate a dict in python using a variable as key path, but getting key error:

testeobj = {'a': 'b', 'c': {'d': {'e':'f'}}}
for k, v in testeobj.items():
    print(f"k:{k}, v:{v}") #OK
nav = "['c']['d']"
print(testeobj[nav]) # testeobj['c']['d'] works good

KeyError: "['c']['d']"

There's any way to do this ?

  • Welcome to Stack Overflow. What exactly are you trying to do with ```nav```? – ewokx Jul 04 '23 at 00:17
  • 1
    You are not going to be able to do this with a string like `"['c']['d']"` — python just thinks this is a string and will try to use is as a key like any other string. See [this thread](https://stackoverflow.com/questions/14692690/access-nested-dictionary-items-via-a-list-of-keys) for some ideas on how you might do this with a list like `['c', 'd']`. – Mark Jul 04 '23 at 00:26

2 Answers2

1

Make nav a list of keys, and then you can iterate over it to navigate the dictionary:

testeobj = {'a': 'b', 'c': {'d': {'e':'f'}}}
nav = ['c', 'd']
o = testeobj
for key in nav:
    o = o[key]
print(o)  # {'e': 'f'}
Samwise
  • 68,105
  • 3
  • 30
  • 44
1

Right, you can't treat a string ("['c']['d']") as Python code like that. There's no native syntax to support something like that, but if you store the path in a list or tuple, like:

nav = ('c', 'd')

Then we can use a loop to retrieve the desired value:

testobj = {'a': 'b', 'c': {'d': {'e':'f'}}}
for k, v in testobj.items():
    print(f"k:{k}, v:{v}") #OK
nav = ('c', 'd')

mark = testobj
for k in nav:
    mark = mark[k]

print(f'path {nav}: {mark}')

Which produces:

k:a, v:b
k:c, v:{'d': {'e': 'f'}}
path ('c', 'd'): {'e': 'f'}

There are also modules such as jmespath and others that allow you to use dot notation to navigate python objects:

import jmespath


testobj = {'a': 'b', 'c': {'d': {'e':'f'}}}
for k, v in testobj.items():
    print(f"k:{k}, v:{v}") #OK
nav = 'c.d'
mark = jmespath.search(nav, testobj)
print(f'path {nav}: {mark}')

Which produces:

k:a, v:b
k:c, v:{'d': {'e': 'f'}}
path c.d: {'e': 'f'}

Or, using / delimited paths in jsonpointer:

import jsonpointer


testobj = {'a': 'b', 'c': {'d': {'e':'f'}}}
for k, v in testobj.items():
    print(f"k:{k}, v:{v}") #OK
nav = '/c/d'
mark = jsonpointer.resolve_pointer(testobj, nav)
print(f'path {nav}: {mark}')

Which produces:

k:a, v:b
k:c, v:{'d': {'e': 'f'}}
path /c/d: {'e': 'f'}
larsks
  • 277,717
  • 41
  • 399
  • 399