简体   繁体   English

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

[英]Free variables treated as globals in Python?

In the Execution Model section of the Python 3.7 reference manual I read the following statement: 在Python 3.7参考手册的“ 执行模型”部分中,我阅读了以下语句:

The global statement has the same scope as a name binding operation in the same block. global语句的作用域与同一块中的名称绑定操作相同。 If the nearest enclosing scope for a free variable contains a global statement, the free variable is treated as a global. 如果最接近的自由变量包围范围包含global语句,则将自由变量视为global语句。

So I typed the following code into the Python Interpreter: 因此,我在Python解释器中输入了以下代码:

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

After calling func1() I would have expected the value of x in the global scope to change to 1 . 调用func1()我希望全局范围内的x值更改为1

What did I get wrong? 我怎么了?

x = 1 in func2 is not a free variable . func2 x = 1 不是自由变量 It's just another local; 这只是另一个当地人。 you are binding to the name and names bound to are, by default, locals unless you tell Python otherwise. 您将绑定到该名称,默认情况下,绑定的名称是本地人,除非您另行告诉Python。

From the 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 . 如果名称绑定在块中,则除非声明为nonlocalglobal ,否则它是该块的局部变量。 [...] If a variable is used in a code block but not defined there, it is a free variable. [...] 如果变量在代码块中使用但未在代码块中定义,则它是一个自由变量。

( Bold emphasis mine ) 加粗强调我的

You bound the name in the block with x = 1 , so it is a local variable in that block, and can't be a free variable. 您将块中的名称与x = 1绑定在一起,因此它是该块中的局部变量,并且不能是自由变量。 So section you found doesn't apply, because that would only apply to free variables: 因此,您发现的部分不适用,因为这仅适用于自由变量:

If the nearest enclosing scope for a free variable contains a global statement, the free variable is treated as a global. 如果最接近的自由变量包围范围包含global语句,则将自由变量视为global语句。

You should not bind x in func2() , because only names that are not binding in the scope are free variables. 您不应在func2()绑定x ,因为只有在范围内绑定的名称才是自由变量。

So this works: 所以这有效:

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

x in func2 is now a free variable; func2 x现在是一个自由变量; it is not defined in the scope of func2 , so picks it up from the parent scope. 它不是在func2的范围内定义的,因此请从父范围中选择它。 The parent scope here is func1 , but x is marked a global there so when reading x for the print() function the global value is used. 此处的父作用域是func1 ,但是x被标记为全局范围,因此当为print()函数读取 x ,将使用全局值。

Contrast this with x not being marked as a global in func1 : 与此相反, xfunc1没有被标记为全局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

Here the global name x is set to 42 , but this doesn't affect what is printed. 此处,全局名称x设置为42 ,但这并不影响打印的内容。 x in func2 is a free variable, but the parent scope func1 only has x as a local name. func2中的x是一个自由变量,但父作用域func1仅将x作为本地名称。

It becomes all the more interesting when you add a new outer-most scope where x is still local : 当您添加新的最外部作用域(其中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 is bound, so not a free variable. x中的outerfunc是有界的,因此不是自由变量。 It is therefore a local in that scope. 因此,它在该范围内是本地的。 However, in func1 , the global x declaration marks x as a global in the nested scrope. 然而,在func1 ,在global x声明标记x作为嵌套斯克罗普一个全球性的。 In func2 x is a free variable, and by the statement that you found, it is treated as a global. func2 x是一个自由变量,根据找到的语句,它被视为全局变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM