I have this piece of code, for some reason when I try to return the path, I get None
instead:
def get_path(dictionary, rqfile, prefix=[]): for filename in dictionary.keys(): path = prefix + [filename] if not isinstance(dictionary[filename], dict): if rqfile in str(os.path.join(*path)): return str(os.path.join(*path)) else: get_path(directory[filename], rqfile, path)
Is there a way to solve this?
The OP has a recursive function, in which the recursive calls misses a return . It thus evaluates to None whenever it recurses.
If we get to the end of any function and we have not explicitly executed any return statement, Python automatically returns the value None. Some functions exists purely to perform actions rather than to calculate and return a result. Such functions are called procedures.
It might seem unexpected, but it is not. The thing is, in Python, every function has a return value. Therefore, if you do not explicitly return anything, None will get returned by default. In the above code, we are printing the return value of test().
Functions often print None when we pass the result of calling a function that doesn't return anything to the print() function. All functions that don't explicitly return a value, return None in Python.
You need to return the recursive result:
else: return get_path(directory[filename], rqfile, path)
otherwise the function simply ends after executing that statement, resulting in None
being returned.
You probably want to drop the else:
and always return at the end:
for filename in dictionary.keys(): path = prefix+[filename] if not isinstance(dictionary[filename], dict): if rqfile in str(os.path.join(*path)): return str(os.path.join(*path)) return get_path(directory[filename], rqfile, path)
because if rqfile in str(os.path.join(*path))
is False
then you end your function without a return
as well. If recursing in that case is not the right option, but returning None
is not, you need to handle that edgecase too.
While I think Martijn Pieters answer addresses the primary issue in his answer (you need to return from the recursive case), I don't think his suggested code will work right.
You're trying to implement a depth-first search for the rqfile
value in the nested dictionary
dict. But your current code doesn't handle the recursive case correctly. It needs to respond appropriately if the result is found in one of its recursive calls, or if the recursive call failed to find the target.
Here's what I think you need, with some things renamed or rearranged for clarity:
def get_path(directory, rqfile, prefix=[]): for filename, value in directory.items(): path_list = prefix + [filename] if not isinstance(value, dict): # base case path = os.path.join(*path_list) if rqfile in path: # Found the file. Do you want to do something return path # with the value here, or is it junk? else: # recursive case try: return get_path(value, rqfile, path_list) # this only returns if except ValueError: # the recursion doesn't raise pass raise ValueError("Requested file not found") # not found here or in children
Example usage:
>>> directory = {"a": "a info", "b": {"c": "b/c info", "d": "b/d info"}, "e": {"f": "e/f info", "g": {"h": "e/g/h info"}}} >>> print(get_path(directory, "h")) e\g\h >>> print(get_path(directory, r'g\h')) e\g\h
If you don't want to raise exceptions when the file is not found, you could also return a sentinel value like None
in place of the last line, and check for the sentinel value it in the recursive case instead of the try
/except
:
result = get_path(value, rqfile, path) if result is not None: return result
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With