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

Free variables treated as globals in Python?

提问人:saveturn 提问时间:10/5/2018 最后编辑:Martijn Pieterssaveturn 更新时间:10/5/2018 访问量:152

问:

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

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

因此,我在 Python 解释器中键入了以下代码:

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

调用后,我本来希望全局范围内的值更改为 .func1()x1

我做错了什么?

python-3.x 作用域 全局 自由变量

评论


答:

3赞 Martijn Pieters 10/5/2018 #1

x = 1in 不是自由变量。这只是另一个当地人;你绑定到名称,绑定到的名称默认是本地人,除非你告诉 Python 另有说明。func2

相同的执行模型文档中:

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

(粗体强调我的)

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

如果 free 变量的最近封闭范围包含语句,则将 free 变量视为全局变量global

不应绑定 ,因为只有作用域中绑定的名称才是自由变量。xfunc2()

所以这有效:

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

xin 现在是一个自由变量;它未在 的作用域中定义,因此从父作用域中选取它。这里的父作用域是 ,但在那里标记为全局,因此在读取函数时使用全局值。func2func2func1xxprint()

与此形成鲜明对比的是,在以下情况下未被标记为全局: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

此处的全局名称设置为 ,但这不会影响打印的内容。 in 是一个自由变量,但父作用域仅具有本地名称。x42xfunc2func1x

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

xin 是绑定的,所以不是自由变量。因此,它是该范围内的本地。但是,在 中,声明在嵌套的 scrope 中标记为全局。In 是一个自由变量,根据您找到的语句,它被视为全局变量。outerfuncfunc1global xxfunc2x