0

I have two code snippets here.

The first one, function create

def creat(pos):
  
  def move(direction, step):
    new_x = pos[0] + direction[0]*step
    new_y = pos[1] + direction[1]*step
    pos[0] = new_x
    pos[1] = new_y

    return pos
  
  return move


player = creat([0,0])
print('after move along x 5 step, the new position is:'+str(player([1,0], 5)))
print('after move along y 10 step, the new position is:'+str(player([0,1], 10)))

and the second, function wrapper

def wrapper(x):
  def func():
    temp = x+1
    x = temp
    return x
  return func

counter = wrapper(0)
for i in range(5):
  print(counter())

The first one works well, but the second raises an error about variable x: local variable x referenced before assignment. I can understand literally what this error means, but I think the variable x should be the same as variable pos in the former snippet. Why the pos is ok but the x not?

Raykie
  • 31
  • 5
  • Does this answer your question? [Don't understand why UnboundLocalError occurs (closure)](https://stackoverflow.com/questions/9264763/dont-understand-why-unboundlocalerror-occurs-closure) ; TL;DR : declare `x` as `nonlocal` at the start of `func` – Tomerikoo Nov 02 '20 at 15:15

1 Answers1

1

The assignment x = temp creates a new local variable that shadows the non-local x defined by wrapper. Even though temp = x + 1 precedes it at run time, it still refers to the local variable x that isn't yet initialized.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thank you for your answer. So you mean when I wrote `x = temp` I create a new local variable, but when I wrote `pos[0] = new_x`, it avoids creating a new variable. right? – Raykie Nov 02 '20 at 15:16
  • Correct. `pos[0]` isn't a variable, but the trigger for calling `pos.__setitem__(0, ...)`. – chepner Nov 02 '20 at 15:21
  • Probably best to include the solution: Add `nonlocal x` to the top of the inner function, so it knows it's supposed to be using the closure scoped `x` the whole time (include when it assigns to it). No need for a `temp` either; may as well just write `x += 1`, `return x`. – ShadowRanger Nov 02 '20 at 15:31