为什么分配给我的全局变量在Python中不起作用?

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的全局变量作用域规则,我遗漏了什么?


全局变量是特殊的。如果试图在函数内部分配一个变量a = value,它会在函数内部创建一个新的局部变量,即使有一个同名的全局变量。要访问全局变量,请在函数内添加global语句:

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,该名称引用值所引用的对象。


函数的执行引入了一个新的符号表,用于函数的局部变量。更准确地说,函数中的所有变量赋值都将值存储在本地符号表中;而变量引用首先查找本地符号表,然后查找封闭函数的本地符号表,然后查找全局符号表,最后查找内置名称表。因此,尽管全局变量可以被引用,但不能在函数中直接赋值(除非在全局语句中命名)。