0

Might someone explain me why this function is not working ? Shouldn't the "nonlocal" statement makes x understandable in g, and therefore in h ?

def f():
    def g():
        nonlocal x
        x= 1
    def h():
        print(x)


>>> SyntaxError: no binding for nonlocal 'x' found

Edit : I used nonlocal in order not to define x anywhere else than in g() : I have to define several variables in my code, and want to do it in a function init_var(). For lisibility, I want to avoid declaring them in my main function. Is there a way to adapt the previous code for this aim ?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Doe Jowns
  • 23
  • 3
  • Does this answer your question? [Python nonlocal statement / keyword](https://stackoverflow.com/questions/1261875/python-nonlocal-statement-keyword) – Karl Knechtel Sep 10 '22 at 10:30

2 Answers2

1

From docs:

Names listed in a nonlocal statement, unlike those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).

Your x is not pre-existing at the point of nonlocal. Try x = None just before def g(): to create a binding for nonlocal to refer to.

The ambiguity problem stated by the docs are easy to see here:

def f():
    def g():
        def h():
            def i():
                def j():
                    nonlocal x

Which functions should have access to x, and which shouldn't? On the other hand, here it is clear:

def f():
    def g():
        def h():
            x = None
            def i():
                def j():
                    nonlocal x

In this case, f and g don't know x, while h, i and j do.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • 1
    One might add that the global namespace does not count as an enclosing scope here. Putting `x = None` outside of function `f` will fail. – user2390182 Jul 30 '18 at 09:55
  • Thanks for this very clear answer. I edited my question, because I want to know if there is a way to avoid this `x = None` declaration, (for the lisibility of the code) – Doe Jowns Jul 30 '18 at 10:01
  • I can't think of a way. Setting up a dictionary or an object with values is much easier; setting up individual variables is hard because they are checked by static analysis. – Amadan Jul 30 '18 at 10:09
  • Another reason why this is required is that Python 3.x implements non-global scopes in a way that's more like a `namedtuple` than a `dict` (such that `locals()` has to create a new `dict` on the fly). Writing `nonlocal x` and then `x = 1` can't create a name that didn't already exist in the appropriate enclosing scope. – Karl Knechtel Sep 10 '22 at 10:37
1

Not sure whether what you are trying really helps readability. If you want to to structure your code, you might want to consider using a class and (instance) attributes. That being said, if you want to avoid multiple assignment lines, you can use attributes of the outer function:

>>> def f():
...   def g():
...     f.a = 5
...   def h():
...     print(f.a)
...   g()
...   h()
... 
>>> f()
5
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • Ok thanks a lot ! Just a question : you have answered the second question, and @Amadan the first, is it possible to concatenate both answers so I can accept the answer ? – Doe Jowns Jul 30 '18 at 11:45