0

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.

Clément Dato
  • 283
  • 2
  • 7
  • No, locals and nonlocals are compiled into lookups in an array, rather than dynamic mappings, and the locals array cannot be re-sized. – Dennis Jan 09 '22 at 23:43
  • Looks like a duplicate. Please, check [Is there a way to get a dict object with nonlocal variables?](https://stackoverflow.com/questions/22438219/is-there-a-way-to-get-a-dict-object-with-nonlocal-variables) – jweyrich Jan 09 '22 at 23:44
  • @jweyrich This might not be a duplicate. The question referred asked about getting a dict of nonlocal variables as read-only. I want to be able to write on them as well. – Clément Dato Jan 09 '22 at 23:50

1 Answers1

1

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.

Dennis
  • 2,249
  • 6
  • 12
  • I am in a denial phase for this misery. Is there any non (`eval` or any string-as-code style) way to achieve this? – Clément Dato Jan 10 '22 at 00:04
  • 1
    I would suggest using a dict, so that you can reference it and update its keys/values as you please. Updating globals and such is kind of a code smell; if you want to be able to reference potentially infinitely many variables by name, you should probably instead just access a dictionary like `my_dict[some_string]`. – Dennis Jan 10 '22 at 00:08
  • I mostly agree. Retrospectively (not pun), the problem in my question is that very rarely there is case (if any) (even in metaprogramming) where we need to care much about the names in local scopes because they cannot escape out, unlike globals which we might need to take much care of sometimes. – Clément Dato Jan 10 '22 at 00:14