Why does assigning to my global variables not work in Python?
我很难理解python的作用域规则。
使用以下脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | a = 7 def printA(): print"Value of a is %d" % (a) def setA(value): a = value print"Inside setA, a is now %d" %(a) print"Before setA" printA() setA(42) print"After setA" printA() |
给了我意想不到的输出:
1 2 3 4 5 | Before setA Value of a is 7 Inside setA, a is now 42 After setA Value of a is 7 |
我希望A值的最后一次打印是42,而不是7。关于python的全局变量作用域规则,我遗漏了什么?
全局变量是特殊的。如果试图在函数内部分配一个变量
1 2 3 4 | a = 7 def setA(value): global a # declare a to be a global a = value # this sets the global value of a |
有关Python命名和绑定规则的详细说明,请参见命名和绑定。
理解这一点的诀窍是,当您使用=分配给一个变量时,您还将它声明为一个局部变量。因此,seta(value)不是更改全局变量a的值,而是将局部变量(碰巧称为a)设置为传入的值。
如果您尝试在seta(value)的开头打印a的值,这会变得更明显,如下所示:
1 2 3 4 | def setA(value): print"Before assignment, a is %d" % (a) a = value print"Inside setA, a is now %d" % (a) |
如果尝试运行此python,将出现一个有用的错误:
1 2 3 4 5 6 | Traceback (most recent call last): File"scopeTest.py", line 14, in setA(42) File"scopeTest.py", line 7, in setA print"Before assignment, a is %d" % (a) UnboundLocalError: local variable 'a' referenced before assignment |
这告诉我们,python已经决定seta(value)函数有一个名为a的局部变量,当您在函数中分配给它时,这个变量是您要更改的。如果不在函数中赋值给(与printa()相同),那么python使用全局变量a。
要将变量标记为全局变量,需要在要使用全局变量的作用域中使用python中的global关键字。在这种情况下,它在seta(value)函数中。所以脚本变成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | a = 7 def printA(): print"Value of a is %d" % (a) def setA(value): global a a = value print"Inside setA, a is now %d" %(a) print"Before setA" printA() setA(42) print"After setA" printA() |
这一行添加告诉python,当您在seta(value)函数中使用变量a时,您谈论的是全局变量,而不是局部变量。
在函数内部,a被视为局部变量,需要定义
global a
在函数内部
python没有其他语言那样的变量概念。您有"某处"的对象,并且您有对这些对象的引用。=用于将这些对象分配给当前命名空间中的引用。
您可以在seta函数的名称空间中创建一个名称a,该名称引用值所引用的对象。
函数的执行引入了一个新的符号表,用于函数的局部变量。更准确地说,函数中的所有变量赋值都将值存储在本地符号表中;而变量引用首先查找本地符号表,然后查找封闭函数的本地符号表,然后查找全局符号表,最后查找内置名称表。因此,尽管全局变量可以被引用,但不能在函数中直接赋值(除非在全局语句中命名)。