Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: reference variable in nested function's outer scope (not global) [duplicate]

I'm trying to recurse a tree and track the path of the traversal up to the point where I find an element that I'm looking for. However, I encounter two issues:

  1. While my current code returns the correct solution, it's a bit hacky. I have to push the current path that's being traversed to final_path, then return final_path[0]. If I just try to set final_path = path, where final_path is defined in the outer scope, it doesn't work. How can I reference the outer scope of the nested function?

  2. In the event the value is not in the tree, I end up with the entire tree traversed in pre-order fashion. Is there any way to structure the code so that I could say "If, at the end of the traversal, we haven't found the target element, then just return [] instead of the full path". I realize that I can just loop through and check each element, but this seems very redundant.

Code:

lftlft = {'val': 3, 'left': None, 'right': {'val': 100, 'left': None, 'right': None}}
rtrt = {'val': 5, 'left': None, 'right': None}
lft = {'val': 2, 'left': lftlft, 'right': {'val': 99, 'left': None, 'right': None}}
rt = {'val': 4, 'left': None, 'right': rtrt}
T = {'val': 1,'left': lft, 'right': rt}

def get_path(root, data, path):
    final_path = []

    def pre_order(tree, path):
        if tree is None:
            return

        path.append(tree['val'])

        if tree['val'] == data:
            final_path.append(path)
            return True

        return pre_order(tree['left'], path[:]) or pre_order(tree['right'], path[:])

    pre_order(root, [])
    print('finalpath', final_path)
    return final_path[0]

get_path(T, 99, [])
like image 827
TheRealFakeNews Avatar asked Feb 07 '23 03:02

TheRealFakeNews


1 Answers

In Python 3.x, you just have to use the keyword nonlocal.

You use it where you'd use global: at the start of your inner function:

def get_path(root, data, path):
    final_path = ...

    def pre_order(tree, path):
        nonlocal final_path
        ...
    ...

    return final_path

Even in Python 2.x, just referencing a variable would automatically grant you read access to the variable - but never write access. Note that if the object referenced is a mutable object, like a list or a dictionary, you can further modify it inside the inner function.

With the introduction of the nonlocal keyword in Python 3.0, you can have full write access to a variable defined in an outer function scope. ]

Your hack of having the inner function writting to a fixed element in an outer-scope list is perhaps the best way to work around it in Python 2.x.

like image 52
jsbueno Avatar answered Feb 08 '23 17:02

jsbueno