This a follow up question to this.
I have two code snippets, one which works and one which does not. The following works:
def decorator(f):
calls_left = [2]
def inner(*args,**kwargs):
if calls_left[0] == 0:
print "limit reached, reseting"
calls_left[0] -= 1
return f(*args,**kwargs)
return inner
@decorator
def foo():
print "Function called"
foo()
foo()
foo()
Produces:
Function called
Function called
limit reached, reseting
Function called
However, if I change calls_left
to a simpe integer, I get an error:
def decorator(f):
calls_left = 2
def inner(*args,**kwargs):
if calls_left == 0:
print "limit reached, reseting"
calls_left -= 1
return f(*args,**kwargs)
return inner
@decorator
def foo():
print "Function called"
foo()
File "decorator_test.py", line 40, in <module>
foo()
File "decorator_test.py", line 25, in inner
if calls_left == 0:
UnboundLocalError: local variable 'calls_left' referenced before assignment
I understand that the list is mutable and the integer is not, but it seems like neither snippet should work. In the first case, my understanding is that calls_left
is redefined when foo
is called, so progressive incrementing shouldn't work. In the second case, I would expect foo
to have access to calls_left
.
Can someone explain this behavior, and the scoping issues surrounding my two calls_left
objects?