Search code examples
pythonscopedynamic-programmingpython-nonlocal

Dynamically binding nonlocal variables


In order to bind a name to a variable from an outer-scope, we can use global or nonlocal keyword, but with the variable name known beforehand, e.g.,

x0 = 0
def f1():
    x1 = 1
    def f2():
        x2 = 2
        def f3():
            x3 = 3
            def h():
                global x0  # cannot use nonlocal, in case you're curious like me
                nonlocal x1, x2, x3  
                x0 += x0
                x1 += x1
                x2 += x2
                x3 += x3
                print(f'x0: {x0}, x1: {x1}, x2: {x2}, x3: {x3}')
            return h
        return f3()
    return f2()

call_h = f1()
call_h()  # print on screen: x0: 0, x1: 2, x2: 4, x3: 6

To dynamically bind a name to a global variable, we can use globals() dictionary instead (globals()['x0']). Is there a way to do this with nonlocal variables? Is there nonlocals()['x1'] sort of thing?

Edit 1: Clarification A suggested duplicate question did not require modifications of the nonlocals, whereas mine does.


Solution

  • No, modifications to locals() may not work, so there is certainly no well-specified function called nonlocals(). From https://docs.python.org/3/library/functions.html#locals :

    locals()

    Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks. Note that at the module level, locals() and globals() are the same dictionary.

    Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

    Also, according to https://www.python.org/dev/peps/pep-0558/, "The semantics of the locals() builtin have historically been underspecified and hence implementation dependent."

    If that's true of locals, the same probably holds for nonlocals.