In the Execution Model section of the Python 3.7 reference manual I read the following statement:
The
globalstatement has the same scope as a name binding operation in the same block. If the nearest enclosing scope for a free variable contains aglobalstatement, the free variable is treated as a global.
So I typed the following code into the Python Interpreter:
x =0
def func1():
global x
def func2():
x = 1
func2()
After calling func1() I would have expected the value of x in the global scope to change to 1.
What did I get wrong?
x = 1infunc2is not a free variable. It's just another local; you are binding to the name and names bound to are, by default, locals unless you tell Python otherwise.From the same Execution model documentation:
(Bold emphasis mine)
You bound the name in the block with
x = 1, so it is a local variable in that block, and can't be a free variable. So section you found doesn't apply, because that would only apply to free variables:You should not bind
xinfunc2(), because only names that are not binding in the scope are free variables.So this works:
xinfunc2is now a free variable; it is not defined in the scope offunc2, so picks it up from the parent scope. The parent scope here isfunc1, butxis marked a global there so when readingxfor theprint()function the global value is used.Contrast this with
xnot being marked as a global infunc1:Here the global name
xis set to42, but this doesn't affect what is printed.xinfunc2is a free variable, but the parent scopefunc1only hasxas a local name.It becomes all the more interesting when you add a new outer-most scope where
xis still local:xinouterfuncis bound, so not a free variable. It is therefore a local in that scope. However, infunc1, theglobal xdeclaration marksxas a global in the nested scrope. Infunc2xis a free variable, and by the statement that you found, it is treated as a global.