在 Python 中将自由变量视为全局变量?
Free variables treated as globals in Python?
在 Python 3.7 参考手册的 Execution Model section 中,我阅读了以下声明:
The global
statement has the same scope as a name binding operation in the same block. If the nearest enclosing scope for a free variable contains a global
statement, the free variable is treated as a global.
所以我在 Python 解释器中输入了以下代码:
x =0
def func1():
global x
def func2():
x = 1
func2()
在调用 func1()
之后,我预计 x
在全局范围内的值会更改为 1
。
我做错了什么?
x = 1
in func2
不是自由变量。这只是另一个本地人;你绑定到名称,默认情况下,绑定到的名称是本地名称,除非你告诉 Python 否则。
来自same Execution model documentation:
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal
or global
. [...] If a variable is used in a code block but not defined there, it is a free variable.
(大胆强调我的)
你用x = 1
绑定了块中的名称,因此它是该块中的局部变量,不能是自由变量。所以你找到的部分不适用,因为那只适用于自由变量:
If the nearest enclosing scope for a free variable contains a global
statement, the free variable is treated as a global.
您不应在 func2()
中绑定 x
,因为只有在范围内 未绑定 的名称才是自由变量。
所以这个有效:
>>> def func1():
... global x
... x = 1
... def func2():
... print(x) # x is a free variable here
... func2()
...
>>> func1()
1
>>> x
1
x
in func2
现在是一个自由变量;它未在 func2
的范围内定义,因此从父范围中选取它。这里的父作用域是 func1
,但是 x
在那里被标记为全局,所以当 reading x
用于 print()
函数时全局使用值。
将此与 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
in outerfunc
是绑定的,所以不是自由变量。因此,它在该范围内是本地的。但是,在 func1
中,global x
声明将 x
标记为嵌套范围中的全局变量。在 func2
x
中是一个自由变量,根据您找到的语句,它被视为全局变量。
在 Python 3.7 参考手册的 Execution Model section 中,我阅读了以下声明:
The
global
statement has the same scope as a name binding operation in the same block. If the nearest enclosing scope for a free variable contains aglobal
statement, the free variable is treated as a global.
所以我在 Python 解释器中输入了以下代码:
x =0
def func1():
global x
def func2():
x = 1
func2()
在调用 func1()
之后,我预计 x
在全局范围内的值会更改为 1
。
我做错了什么?
x = 1
in func2
不是自由变量。这只是另一个本地人;你绑定到名称,默认情况下,绑定到的名称是本地名称,除非你告诉 Python 否则。
来自same Execution model documentation:
If a name is bound in a block, it is a local variable of that block, unless declared as
nonlocal
orglobal
. [...] If a variable is used in a code block but not defined there, it is a free variable.
(大胆强调我的)
你用x = 1
绑定了块中的名称,因此它是该块中的局部变量,不能是自由变量。所以你找到的部分不适用,因为那只适用于自由变量:
If the nearest enclosing scope for a free variable contains a
global
statement, the free variable is treated as a global.
您不应在 func2()
中绑定 x
,因为只有在范围内 未绑定 的名称才是自由变量。
所以这个有效:
>>> def func1():
... global x
... x = 1
... def func2():
... print(x) # x is a free variable here
... func2()
...
>>> func1()
1
>>> x
1
x
in func2
现在是一个自由变量;它未在 func2
的范围内定义,因此从父范围中选取它。这里的父作用域是 func1
,但是 x
在那里被标记为全局,所以当 reading x
用于 print()
函数时全局使用值。
将此与 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
in outerfunc
是绑定的,所以不是自由变量。因此,它在该范围内是本地的。但是,在 func1
中,global x
声明将 x
标记为嵌套范围中的全局变量。在 func2
x
中是一个自由变量,根据您找到的语句,它被视为全局变量。