Search code examples
python-3.xrecursionscoping

scoping of recursive functions within functions in python


Why does the following work:

def rec(a, b, c):
    global nmb_calls
    nmb_calls += 1
    # other stuff
    rec(...)

p_list = []
nmb_calls = 0 
rec(a=p_list, b, c)
print(p_list)

but something like:

def rec(a, b, c):
    nonlocal nmb_calls
    nmb_calls += 1
    # other stuff
    rec(...)

def call_rec(usr_b):
    p_list = []
    nmb_calls = 0
    rec(a=p_list, b=usr_b, c)
    return p_list

fail with the error: SyntaxError: no binding for nonlocal 'nmb_calls' found

I thought nonlocal means that rec would look up in the enclosing scope (that of call_rec), find nmb_calls and use that?


Solution

  • The reason the second case doesn't work is the way you're calling it in call_rec is not an enclosing scope that works with nonlocal. You'd have to do something like the following to call rec() using nonlocal for nmb_calls:

    def enclosing_function():
        def rec(a, b, c):
            nonlocal nmb_calls
            nmb_calls += 1
            # other stuff
            #rec(...)
    
        p_list = []
        nmb_calls = 0
        rec(a=p_list, b=usr_b, c=None)
        return p_list
    

    Also, just a heads up that you can't call rec without specifying the c parameter in the same way as you did for a and b.

    So this doesn't work:

    rec(a=p_list, b=usr_b, c)
    

    but you can do the reverse:

    rec(a, b, c=None)