Python全局变量/范围混乱

Python global variable/scope confusion

本问题已经有最佳答案,请猛点这里访问。

我开始自学python,并注意到一些与全局变量和范围有关的奇怪事情。当我运行这个时:

1
2
3
4
5
6
x = 2
y = 3
z=17
def add_nums():
    y = 6
    return z+y

23的结果打印出来…但是,当我将回报率扩展为:

1
2
3
4
5
6
7
x = 2
y = 3
z=17
def add_nums():
    y = 6
    z = z + y
    return z

我在第6行得到以下错误:

1
2
3
Local name referenced but not bound to a value.
A local name was used before it was created. You need to define the    
method or variable before you try to use it.

我很困惑为什么我会在这里得到一个错误,因为z是全局的一个可访问的。


当变量位于等号的左侧时,python将创建一个局部变量。当变量位于等号的右侧时,python将尝试查找局部变量,如果找不到局部变量,则它将使用全局变量。在您的示例中,z位于等号的左右两侧,为了避免含糊不清,python会引发一个错误。您需要使用global语法来避免这种情况:

1
2
3
4
5
6
7
8
x = 2
y = 3
z=17
def add_nums():
    global z
    y = 6
    z = z + y
    return z

python通过绑定操作确定作用域。赋值是一个绑定操作,和导入一样,在except .. aswith .. asfor循环中使用名称作为目标,或者通过创建函数或类。

当名称绑定到作用域中时,它是该作用域的本地名称。如果一个名称被使用但没有被绑定,那么它是非本地的;编译器将在编译时确定该范围应该是什么。在您的情况下,除了全局作用域之外没有父作用域,因此任何未绑定到的名称都被视为全局名称。

由于第二个示例绑定到z(您使用了z =,一个赋值),所以该名称是函数的本地名称。

如果名称在作用域中绑定到,但您希望告诉python它应该是全局的,则需要显式地这样做:

1
2
3
4
5
6
7
8
x = 2
y = 3
z=17
def add_nums():
    global z
    y = 6
    z = z + y
    return z

global z行告诉编译器,z应该是全局的,即使您绑定到它。


让我们分析一下标记线。

1
2
3
4
5
6
7
x = 2
y = 3
z = 17
def add_nums():
    y = 6
    z = z + y  <--- THIS LINE
    return z

Z…创建新的局部变量=…我们要给它赋值Z…这个变量存在(新的局部变量),但它还没有值。+Y…未达到此部分。

结果是一条错误消息"unboundlocalerror:local variable'z'referenced before assignment"。


如果您希望函数体中的名称yz在为全局变量赋值时引用它们,则必须这样声明它们:

1
2
3
4
5
6
7
8
9
x = 2
y = 3
z=17
def add_nums():
    global y
    global z
    y = 6
    z = z + y
    return z

否则,当您在函数内对变量yz执行赋值时,您将创建只存在于函数局部范围内的不同名称。

正如注释中指出的,如果全局变量是可变的(即在列表中附加一些内容),则可以引用它,甚至可以对其进行修改,而不必显式地将其声明为全局变量,只要不尝试为其赋值。