在Python 3.7参考手册的执行模型部分,我读到了以下语句:
global
语句的作用域与同一块中的名称绑定操作的作用域相同。如果自由变量的最近封闭作用域包含global
语句,则该自由变量将被视为全局变量。
所以我在 Python 解释器中键入了以下代码:
x =0
def func1():
global x
def func2():
x = 1
func2()
调用func1()
后,我本以为全局范围内x
的值会更改为1
。
我做错了什么?
func2
中的x = 1
不是自由变量。这只是另一个当地人;默认情况下,你绑定到的名称和绑定为局部变量的名称,除非您另行通知 Python。
来自同一执行模型文档:
如果名称绑定在块中,则它是该块的局部变量,除非声明为
nonlocal
或global
。[...]如果变量在代码块中使用但未在其中定义,则它是自由变量。
(粗体强调我的(
你用x = 1
绑定了块中的名称,所以它是该块中的局部变量,不能是自由变量。所以你找到的部分不适用,因为这只适用于自由变量:
如果自由变量的最近封闭作用域包含
global
语句,则该自由变量将被视为全局变量。
你不应该在func2()
中绑定x
,因为只有未绑定在作用域中的名称才是自由变量。
所以这有效:
>>> def func1():
... global x
... x = 1
... def func2():
... print(x) # x is a free variable here
... func2()
...
>>> func1()
1
>>> x
1
func2
中的x
现在是一个自由变量;它没有在func2
的作用域中定义,所以从父作用域中选取它。这里的父作用域是func1
,但x
在那里被标记为全局,因此在读取print()
函数的x
时,将使用全局值。
与此形成对比的是x
func1
中未标记为全局:
>>> def func1():
... x = 1
... def func2():
... print(x) # x is free variable here, now referring to x in func1
... func2()
...
>>> x = 42
>>> func1()
1
此处的全局名称x
设置为42
,但这不会影响打印的内容。func2
中的x
是一个自由变量,但父作用域func1
只有x
作为本地名称。
当您添加一个新的最外层范围时,x
仍然是本地的,它会变得更加有趣:
>>> def outerfunc():
... x = 0 # x is a local
... def func1():
... global x # x is global in this scope and onwards
... def func2():
... print('func2:', x) # x is a free variable
... func2()
... print('outerfunc:', x)
... func1()
...
>>> x = 42
>>> outerfunc()
outerfunc: 0
func2: 42
>>> x = 81
>>> outerfunc()
outerfunc: 0
func2: 81
x
中的outerfunc
是绑定的,因此不是自由变量。因此,它是该范围内的本地。然而,在func1
中,global x
声明将x
标记为嵌套的 scrope 中的全局。Infunc2
x
是一个自由变量,根据您找到的语句,它被视为全局变量。