0

The following code works perfectly:

def f():
    a = []
    def g(x):
        a.append(x)
        print(a)
    return g

a = f()
a(0)
a(1)

But when I replace a.append(x) with a += [x] I get an UnboundLocalError: local variable 'a' referenced before assignment usually solved with a nonlocal a declaration inside nested function.

Why this difference of behaviour on closures?

david
  • 1,302
  • 1
  • 10
  • 21
  • For the same reason this error always occurs, because your assignment statement to a variable, in this case, `a` when you do `a += [x]` make is local by default, so when you try to reference it, doesn't exist yet. – juanpa.arrivillaga Apr 21 '22 at 07:43
  • Now, `a.append(x)` works because `a` is never assigned to, so it is a free variable, and it resolves to the variable in the enclosing scope. This is the same reason you can do `b = a + [x]` but not `a = a + [x]` You can think of `a += [x]` as `temp = a.__iadd__(x); a = temp; del temp` – juanpa.arrivillaga Apr 21 '22 at 07:45
  • Doesn't `+=` syntax refers to `__iadd__` method? So `+=` doesn't seem to be a real assignement... – david Apr 21 '22 at 07:53
  • 1
    `__iadd__` is a hook that can be called (if implemented, otherwise it falls back to `__add__` and it will try `__radd__` of the right operand if the left has neither, then it will raise a TypeError) when `a += [x]` is executed, but it *also* assigns the result of that to `a`. So it *is* an assignment. – juanpa.arrivillaga Apr 21 '22 at 07:56
  • 2
    Just check out `dis.dis("x += 1")` and you'll see a `STORE_NAME` for `x` – juanpa.arrivillaga Apr 21 '22 at 08:07

0 Answers0