2

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

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

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

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

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

我做错了什么?

4

1 回答 1

3

x = 1infunc2 不是自由变量。这只是另一个本地人;默认情况下,您绑定到的名称和绑定的名称是本地人,除非您另外告诉 Python。

来自相同的执行模型文档

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

粗体强调我的

您用 绑定了块中的名称x = 1,因此它是该块中的局部变量,不能是自由变量。所以你发现的部分不适用,因为那只适用于自由变量:

如果自由变量的最近封闭范围包含global语句,则自由变量被视为全局变量。

您不应该绑定xin func2(),因为只有在范围内绑定的名称才是自由变量。

所以这有效:

>>> def func1():
...     global x
...     x = 1
...     def func2():
...         print(x)  # x is a free variable here
...     func2()
...
>>> func1()
1
>>> x
1

xinfunc2现在是一个自由变量;它未在 的范围内定义func2,因此从父范围中获取。这里的父作用域是func1,但x在那里被标记为全局,因此在读取 x函数时使用print()全局值。

x将此与未标记为全局 in 进行对比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,但这不会影响打印的内容。xinfunc2是一个自由变量,但父范围func1x作为本地名称。

当您添加一个仍然是本地的新最外层范围时,它变得更加有趣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

xinouterfunc是有界的,所以不是自由变量。因此,它在该范围内是本地的。但是,在 中func1global x声明在嵌套的 scrope 中标记x为全局。Infunc2 x是一个自由变量,根据您找到的语句,它被视为全局变量。

于 2018-10-05T13:23:36.847 回答