我开始自学python,并注意到全局变量和作用域的一些奇怪之处。当我运行这个:
x = 2
y = 3
z=17
def add_nums():
y = 6
return z+y
输出23的结果…然而,当我将返回展开为:
x = 2
y = 3
z=17
def add_nums():
y = 6
z = z + y
return z
我在第6行得到以下错误:
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
语法来避免这种情况:
x = 2
y = 3
z = 17
def add_nums():
global z
y = 6
z = z + y
return z
Python通过绑定操作来确定作用域。赋值是一种绑定操作,就像导入一样,在except .. as
、with .. as
或for
循环中使用名称作为目标,或者通过创建函数或类。
当一个名称被绑定到一个作用域中时,它是该作用域的局部名称。如果使用了名称但没有绑定,则它是非本地的;编译器将在编译时确定作用域应该是什么。在您的示例中,除了全局作用域之外没有父作用域,因此任何未绑定到的名称都被认为是全局的。
由于第二个示例绑定到z
(您使用了z =
,一个赋值),因此该名称是函数的局部名称。
如果一个名字被绑定在一个作用域中,但你想告诉Python它应该是全局的,你需要显式地这样做:
x = 2
y = 3
z=17
def add_nums():
global z
y = 6
z = z + y
return z
global z
行告诉编译器z
应该是一个全局变量,,即使你绑定到它。
让我们分析一下标记的行。
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' reference before assign "
如果您希望函数体内的名称y
和z
在您为它们赋值时引用您的全局变量,您必须像这样声明它们:
x = 2
y = 3
z=17
def add_nums():
global y
global z
y = 6
z = z + y
return z
否则,当你在函数内对变量y
和z
赋值时,你会创建不同的名字,这些名字只存在于函数的局部作用域中。
正如在评论中指出的,你可以引用一个全局变量,甚至修改它,如果它是可变的(即追加一些东西到一个列表),而不显式地声明它是全局的,只要你不试图分配给它。