Let's break these down one-by-one. Python's scoping rules are a bit unhinged sometimes. The basic idea is that if you ever assign to a variable inside of a given function, then Python assumes that that variable is local to that particular function.
def main_function():
b = 'b'
def nested_function():
print(b)
nested_function()
main_function()
Here, you never assign to b
inside of nested_function
, so Python sees no need to create a new variable. Instead, it inherits the one from its enclosing scope.
def main_function():
b = 'b'
def nested_function():
b = 'value change'
nested_function()
main_function()
Here, you do assign to it, so you get a new variable. The b
you assign to inside of nested_function
is unrelated to the one inside of main_function
. They just happen to share a name.
def main_function():
b = 'b'
def nested_function():
print(b)
b = 'value change'
nested_function()
main_function()
Here, you do assign, so Python makes a new variable inside of the function, and every reference to b
inside the nested function refers to that new variable, so it's as if you did this.
def main_function():
b_0 = 'b'
def nested_function():
print(b_1)
b_1 = 'value change'
nested_function()
main_function()
So you're trying to print out b_1
before any value has been assigned to it, hence the error.
If b
was a module-level variable, you would use the global
keyword to mark it as such inside the function. In your case, it's a local variable; it's just not local to the immediately enclosing function. So we use the nonlocal
keyword.
def main_function():
b = 'b'
def nested_function():
nonlocal b
print(b)
b = 'value change'
nested_function()
main_function()
nonlocal b
says "I know I'm assigning to b
, but I actually mean to use the one from the enclosing scope".