def foo():
a = 0
def bar():
a += 1
bar()
foo()
Why is it that this code does not execute when a is an immutable type, but does execute when it is mutable (a list, for example)?
def foo():
a = 0
def bar():
a += 1
bar()
foo()
Why is it that this code does not execute when a is an immutable type, but does execute when it is mutable (a list, for example)?
I don't think the other answers narrate the entire story, so here's my 2 cents.
The scope does not differ between types. That's not what's happening here.
Rebinding a name, regardless of what that name refers to, will always cause an unbound local error to occur.
Some types in Python are mutable (once created, a value can be changed), and list is one of them. Some are immutable, and changing a value of these types requires creating a new object.
So, with the first example,
def foo():
a = 0
def bar():
a += 1
bar()
foo()
This doesn't work because you effectively have an assignment taking place here, a = a + 1
. You can use non-local
to make the above work, that being besides the point.
Doing the same thing with a list:
def foo():
a = []
def bar():
a.append(1)
bar()
foo()
This does indeed work. There is no assignment taking place here.
You can't re-bind the name to a different object, but if the object is mutable, you can modify its contents.
Now, there's 2 more cases you should be aware of.
def foo():
a = []
c = []
def bar():
a = c + [1]
bar()
print(a)
print(c)
foo()
This will work, however you should note that the a
inside bar()
now is local to bar, and the print() statement should reflect that.
But here's a gotcha
def foo():
a = []
def bar():
a = a + [1] #or even a += [1], doesn't matter
bar()
print(a)
foo()
This won't work! (And it's important you contrast this snippet with the first snippet, because that addresses why this has nothing to do with scopes. Take a minute to read it again.)
So this doesn't work and it's important to understand it.
If there is an assignment to a variable inside a function, that variable is considered local.
Now, in the last case, when we did a = c + 1
, it was more like a_local = c_nonlocal + 1
.
In this case, a = a + 1
is a_local = a_local + 1
and hence, that will indeed cause an error.
This is why, Rebinding a name, regardless of what that name refers to, will always cause an unbound local error to occur.
In the case earlier(The third snippet), it wasn't rebinding it - it was creating a local variable.
In the latter case(The fourth snippet), it was infact rebinding and hence the error.
There is a keyword nonlocal
which is used to access nonlocal variables.
The nonlocal keyword is used to work with variables inside nested functions, where the variable should not belong to the inner function. --w3schools.com
def foo():
a = 0
def bar():
nonlocal a
a += 1
bar()
foo()
Thank you
That is because you are not returning any value from either functions and the second a
is only local
to the function bar()
.
Try using the nonlocal keyword like this:
def foo():
a = 0
def bar():
nonlocal a
a += 1
return a
return bar()
print(foo())
Output
1