Because you are doing an assignment and the scope has to be clarified.
Your case:
a = 3
def b():
a = a + 1
return a
print(b())
Output:
Traceback (most recent call last):
File "./tests/test1.py", line 12, in <module>
print(b())
File "./tests/test1.py", line 9, in b
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
When you do the assignement a = ...
you have created always a local variable unless it has been declared global
which is not the case. Local resolution takes precedence.
Your example would obviously work with:
a = 3
def b():
global a
a = a + 1
return a
print(b())
Which outputs:
4
But using globals, imho, should not be the way and hence passing a
as a parameter to function b
would be it:
a = 3
def b(a):
a = a + 1
return a
print(b(a))
Which agains produces the expected 4
.
EDIT:
Following the edition in the OP: you can always "reference" the global scope (and parent scope). But if you make assignments they take place in the local scope.
If your code (which is wronly indented and contains a new c
which isnt' anywhere) is meant to do this:
a = 3
def b():
def c():
print(a)
return c()
b()
It works ... and prints 3
because there is NO assignment and only referencing. As soon as you executing an assignment a
would again be created in the local scope.