I am trying to write a function which searches for a key in an arbitrarily deep nested dict
and returns its value(s) together with the path(s) of ancestor keys -
# find_key.py
def find_key(key, targ, path=[]):
""" Search an aribitarily deep nested dict `targ` for key `key`.
Return its value(s) together with the path(s) of ancestor keys.
"""
if key == targ:
yield v, path
if isinstance(targ, dict):
for k, v in targ.items():
if k == key:
yield v, path
else:
find_key(key, v, path.append(k))
path.pop()
# test code
targ_1 = {'a': 1, 'b': {'b': 2, 'c': 3}, 'd': {'e': {'f': 4}}}
tests = {'test_a': {'key' : 'a', 'targ': targ_1, 'expect': [(1, [])]},
'test_b': {'key' : 'b', 'targ': targ_1, 'expect': [({'b': 2, 'c': 3}, []), (2, ['b'])]},
'test_c': {'key' : 'c', 'targ': targ_1, 'expect': [(3, ['b'])]},
'test_d': {'key' : 'd', 'targ': targ_1, 'expect': [({'e': {'f': 4}}, [])]},
'test_e': {'key' : 'e', 'targ': targ_1, 'expect': [({'f': 4}, ['d'])]},
'test_f': {'key' : 'f', 'targ': targ_1, 'expect': [(4, ['d', 'e'])]}}
for k, v in tests.items():
if list(find_key(v['key'], v['targ'])) == v['expect']:
print(k, 'OK')
else:
print(k, 'actual:', list(find_key(v['key'], v['targ'])))
print(k, 'expected:', v['expect'])
Executing the code shows that many test cases failed -
(3.8) $ python find_key.py
test_a OK
test_b actual: [({'b': 2, 'c': 3}, [])]
test_b expected: [({'b': 2, 'c': 3}, []), (2, ['b'])]
test_c actual: []
test_c expected: [(3, ['b'])]
test_d OK
test_e actual: []
test_e expected: [({'f': 4}, ['d'])]
test_f actual: []
test_f expected: [(4, ['d', 'e'])]
I suspect the problem lies in the recursive call find_key
so I inserted a breakpoint()
above the call and re-executed the file -
(3.8) $ python find_key.py
> find_key.py(15)find_key()
-> find_key(key, v, path.append(k))
(Pdb) s
--Call--
> find_key.py(1)find_key()
-> def find_key(key, targ, path=None):
(Pdb) s
GeneratorExit
> find_key.py(1)find_key()
-> def find_key(key, targ, path=None):
(Pdb) s
--Return--
> find_key.py(1)find_key()->None
-> def find_key(key, targ, path=None):
(Pdb) s
> find_key.py(16)find_key()
-> path.pop()
(Pdb)
As you can see, Pdb does not step into the recursively called find_key
but instead issues messages GeneratorExit
and --Return--
. How can I debug this issue?