I am quite new to Python and try to understand how it works. Now I ran into a scoping problem that puzzles me.
I think I do understand the following example. I construct a function with an empty local namespace (please correct me if my terminology is not right). When called, it has to print the value of a variable x. That is not in the namespace of the function, so Python looks in the enclosing namespace, finds x there and prints the value.
x = 12
def f():
print(locals())
print(x)
f()
Returns:
[]
12
I learned from various sources that the namespace of a function is constructed during the evaluation of the function and vanishes when the function evaluation is over. That is what I see in the next example. When the function evaluation starts, only the function argument is in the namespace. Then assignments to y and z are done, resulting in y and z successively being placed in the local name space, as shown by the three printing results in the output.
def f(x):
print(locals())
y = 20
print(locals())
z = x+y
print(locals())
return z
f(10)
Returns:
{'x': 10}
{'x': 10, 'y': 20}
{'x': 10, 'y': 20, 'z': 30}
30
Now the subtlety I fail to understand. In the first example, I include an assignment to x just after the print statement.
x = 12
def f():
print(locals())
print(x)
x = 24
f()
Result:
{}
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
f()
File "<pyshell#5>", line 5, in f
print(x)
UnboundLocalError: local variable 'x' referenced before assignment
When x has to be printed, it is not yet in the local namespace. So I expected to see the outside value 12. But Python seems to be aware of the fact that x is a local variable of the function and produces an UnboundLocalError.
This suggest to me that when the definition of a function is read, Python creates some or other list with the string names for the local variables, I think including default values for the arguments. This list is then used during the evaluation of the function for constructing the local namespace. Where is this list stored? Very likely, I am completely wrong. Any help in understanding what is going on here is highly appreciated.