我们定义一个函数,它读取两个变量的值:一个是局部变量a,是函数的参数;另一个是变量b,这个函数没有定义它。
def f1(a):
print(a)
print(b)
f1(3)
3
Traceback (most recent call list)
File"<stdin>",line 1,in <module>
File"<stdin>",line 3,in f1
NameError:global name 'b' is not defined
出现错误并不奇怪。如果先给全局变量b赋值,然后再调用f,那就不会出错:
b = 6
f1(3)
3
6
看一下示例f2函数。前面两行代码与示例中f1一样,然后为b赋值,再打印它的值。可是在赋值之前,第二个print失败了。
b = 6
def f2(a):
print(a)
print(b)
b = 9
f2(3)
3
Traceback(most recent call list)
File "<stdin>",line 1,in <module>
File "<stdin>" line 3,in f2
UnbundLocalError:local variable 'b' referenced before assignmengt
注意,首先输出了3,这表明print(a)语句执行了。但是第二个语句print(b)执行不了。一开始我很吃惊,我觉得会打印6,因为有个全局变量b,而且是在print(b)之后为局部变量b赋值
可事实是,python变异函数的定义体时,它判断b是局部变量,因为在函数中给它赋值 了。生成的字节码证实了这种判断,python会尝试从本地环境获取b。后面调用f2(2)时,f2的定义体会获取并打印局部变量a的值,但是尝试获取局部变量b的值时,发现b没有绑定值。
这不是缺陷,而是设计的选择:python不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。这比Javascrapt的行为好多了,Javascript也不要求声明变量,但是如果忘记把变量声明为局部变量(使用var),可能会在不知情的情况下获取全局变量。
如果在函数中赋值时想让解释器b当成全局变量,要使用global声明:
b = 6
def f3(a):
global b
print(a)
print(b)
b = 9
f3(3)
3
6
b
9
f3(3)
3
9
b = 30
b
30