# result and path should be outside of the scope of find_path to persist values during recursive calls to the function result = [] path = [] from copy import copy # i is the index of the list that dict_obj is part of def find_path(dict_obj,key,i=None): for k,v in dict_obj.items(): # add key to path path.append(k) if isinstance(v,dict): # continue searching find_path(v, key,i) if isinstance(v,list): # search through list of dictionaries for i,item in enumerate(v): # add the index of list that item dict is part of, to path path.append(i) if isinstance(item,dict): # continue searching in item dict find_path(item, key,i) # if reached here, the last added index was incorrect, so removed path.pop() if k == key: # add path to our result result.append(copy(path)) # remove the key added in the first line if path != []: path.pop() # default starting index is set to None find_path(di,"location") print(result) # [['queryResult', 'outputContexts', 4, 'parameters', 'DELIVERY_ADDRESS_VALUE', 'location'], ['originalDetectIntentRequest', 'payload', 'inputs', 0, 'arguments', 0, 'extension', 'location']]