目录
全局和局部变量
###代码一
count = 0
def f():
print(count)
f()
上面的count就是个全局变量,调用f函数的结果就是输出0
###代码二
count = 1
def f():
count = count+1
print(count)
f()
运行上面代码就会报错
UnboundLocalError: local variable 'count' referenced before assignment
赋值前引用了局部变量
再来个代码
###代码三
count = 1
def f():
print(count)
count = count+1
f()
发现依然报错: UnboundLocalError: local variable 'count' referenced before assignment
原因
python 在对代码编译的时候如果出现对变量进行赋值的操作,会默认将变量视作一个局部变量,不管外部是否有初始化过。如果外部有,在这个赋值的局部空间内(即上面代码的f()函数里),这些同名字的外部变量都视作不可见。
因此回到上述的代码块三,由于出现赋值,编译时f()内的count是局部变量,因此在引用时会在f() 的范围内寻找是否有count初始化,发现没有,所以报UnboundLocalError,同样print(count)时也会报错,即使print是先于count = count + 1的。
注意:这和赋值语句出现的顺序没有关系,即使赋值语句在后,前面调用了的变量依然是局部变量
而在在代码块一 中由于f()中未出现赋值情况,python 会在全局变量中寻找count,因此不会报错
在闭包中同样有上述例子
###代码四
def a():
count = 1
def b():
print(count)
count = count+1
b()
a()
报错:UnboundLocalError: local variable 'count' referenced before assignment
还有个老生常谈的例子
###代码五
def a():
count = 1
def b():
count = 2
b()
print(count)
a()
这里的b()中count的赋值改变的是b()中局部变量的,不影响上一层a()中count的值
解决办法
global and nonlocal
常规的解决方法一般是用global关键字进行声明
###代码六
count = 1
def f():
global count
print(count)
count = count+1
f()
局部需要修改全局变量时可以用global进行声明
但是在闭包中使用这个global关键字可能会报错
###代码七
def a():
count = 1
def b():
global count
count = count+1
b()
print(count)
a()
NameError: name 'count' is not defined
###代码八
def a():
count = 1
print(count)
print(id(count))
def b():
global count
count = 2
print(id(count))
print(count)
b()
a()
print(count)
这个代码不会报错
结果
代码七报错是因为只声明全局变量count,但是未在代码中找到全局变量count,最后count = count+1执行不了,这里的a()中的count其实是b()的上层变量,是属于局部变量。
使用pycharm的话,会发现此时count处有个灰色虚线
未定义的全局变量count
而代码八中先声明global后,count = 2,又重新赋值了,最后结果那样是因为global使count的作用域不在局部而在全局。局部函数执行完之后,不销毁函数内部以global定义的变量。
这样的问题我们可以使用下面的nonlocal关键字来解决,但是如果我们就是想用global呢?
可以这样:
def a():
global count
count = 1
def b():
global count
count = count+1
print(count)
b()
print(count)
a()
结果
我们在外部函数用global声明个全局变量,再在内部函数使用的时候进行声明就行
当然还可以使用nonlocal,对于在闭包中一般常用的是nonlocal关键字
nonlocal,非局部声明变量指代的已有标识符是最近外面函数的已声明变量,一般就是类似于闭包的上一层,在递归中可以使用
###代码九
def a():
count = 1
def b():
nonlocal count
count = count+1
b()
print(count)
a()
上述代码逻辑是先定义个在a函数范围的局部变量count,接着定义了个b函数,在b函数中声明count不是局部变量
nonlocal和global不同,在使用前必须事先声明,那么函数b中的nonlocal就会报错
###代码十
def a():
def b():
nonlocal count
count = 1
print(count)
b()
a()
SyntaxError: no binding for nonlocal 'count' found
可执行的代码
def a():
count = 1
def b():
nonlocal count
count = count+1
print(count)
b()
print(count)
a()
结果
总结
当你尝试在python中对一个变量进行赋值的时候,python会在编译的时候默认该变量是一个局部变量。
要明确 nonlocal 关键字是定义在闭包里面的(不定义在闭包里会抛异常SyntaxError: nonlocal declaration not allowed at module level)。
nonlocal只能在封装函数中使用,在外部函数先进行声明,在内部函数进行nonlocal声明。
当然,为了防止因为局部和全局的报错最好还是调用参数
滴滴滴,说唱博士·TANGLOOPY 你看完了吗