在 Python 中被视为全局变量的自由变量?



在Python 3.7参考手册的执行模型部分,我读到了以下语句:

global语句的作用域与同一块中的名称绑定操作的作用域相同。如果自由变量的最近封闭作用域包含global语句,则该自由变量将被视为全局变量。

所以我在 Python 解释器中键入了以下代码:

x =0
def func1():
global x
def func2():
x = 1
func2()

调用func1()后,我本以为全局范围内x的值会更改为1

我做错了什么?

func2中的x = 1不是自由变量。这只是另一个当地人;默认情况下,你绑定到的名称和绑定为局部变量的名称,除非您另行通知 Python。

来自同一执行模型文档:

如果名称绑定在块中,则它是该块的局部变量,除非声明为nonlocalglobal[...]如果变量在代码块中使用但未在其中定义,则它是自由变量。

(粗体强调我的(

你用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时,将使用全局值。

与此形成对比的是xfunc1中未标记为全局:

>>> 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 中的全局。Infunc2x是一个自由变量,根据您找到的语句,它被视为全局变量。

最新更新