首先我们看一段代码,是不是有很多疑惑
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam) ''' 输出: After local assignment: test spam After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam In global scope: global spam '''
一直看不明白第三个为什么时这样,补充一下
x = 0 def outer(): x = 1 def inner(): global x x = 2 print("inner:", x) inner() print("outer:", x) outer() print("global:", x) # inner: 2 # outer: 1 # global: 2
我们忘记了,如果局部变量与全局变量变量名一样,则优先调用局部变量,因此上面的难题解决了
首先我们先了解全局变量和局部变量
1.全局变量和局部变量的区别在于作用域,全局变量在整个py文件中声明,全局范围内可以使用;局部变量是在某个函数内部声明的,只能在函数内部使用,如果超出使用范围(函数外部),则会报错
A = 100 # 全局变量一般用大写字母表示 def func(): a = 50 # 局部变量一般用小写字母表示 print(a+A) func() #150 print(A) #100 print(a) # 报错信息NameError: name 'a' is not defined,说明局部变量只能在函数内使用
2.在函数内部,如果局部变量与全局变量变量名一样,则优先调用局部变量
A = 100 def func(): A=250 print(A) print(A) # 打印全部变量 100 func() # 局部变量 250
3.如果想在函数内部改变全局变量,需要在前面加上global关键字,在执行函数之后,全局变量值也会改变
A = 100 def func(): global A A = 200 print(A) print(A) # 打印全局变量 100 func() # 局部变量 200 print(A) # 改变后的全局变量 200
4.如果全局变量是列表类型(针对全局变量如果是可变对象,可以对内部元素进行操作),可以通过list的列表方法去对列表进行修改,并且可以不用global来声明
list_1 = [1,2,56,"list"] def changeList(): list_1.append("over") print(list_1) changeList() #[1, 2, 56, 'list', 'over'] print(list_1) #[1, 2, 56, 'list', 'over']
5.如果函数中有global关键字,变量本质上就是全局变量,可读取可赋值
NAME = "nicholas" print(1,NAME) def change_NAME(): global NAME NAME = "niubi" print("change_NAME", NAME) change_NAME() print(2,NAME) #有global,定义的就是全局变量,可以赋值以及修改
要注意global的位置,如果需要global对全局变量进行修改这里的global不能放在name = "nick"下面
6.如果全局变量是不可变对象(非list)等,我们就不能在函数里面去修改全局变量,但是我们想修改,那么就可以使用global
count = 0 def global_test(): count += 1 print(count) global_test() #UnboundLocalError: local variable 'count' referenced before assignment
nonlocal
python变量引用顺序:从当前作用域开始寻找变量,如果没找到就往上一层作用域寻找,没找到就再上一层......
即:当前作用域局部变量->外层作用域变量->再外层作用域变量->......->当前模块全局变量->pyhton内置变量
global:全局变量
nonlocal:外层嵌套函数的变量
使用总结:
1、局部作用域改变全局变量用global, global同时还可以定义新的全局变量
2、内层函数改变外层函数变量用nonlocal, nonlocal不能定义新的外层函数变量,只能改变已有的外层函数变量(外层直到全局作用域的下一层都没有,会报错),同时nonlocal不能改变全局变量
当没有nonlocal时
a = 10 # a1 当前模块全局变量 def outer(): a = 9 # a2 当前outter作用域局部变量 def inner(): a = 8 # a3 当前inner作用域局部变量 print(a) # a3 8, 在inner的局部作用域中找到了a3 inner() # inner()函数结束,a3作为inner局部变量被释放 print(a) # a2 9,在outer局部作用域中找到a2 outer() # outer()函数结束,a2作为outer局部变量被释放 a ''' 8 9 10 '''
用于在内层函数中改变外层函数变量
a = 10 # a1 当前模块全局变量 def outer(): a = 9 # a2 outer局部变量 def inner(): nonlocal a a = 8 # a3 既是inner局部变量,又是外层outer局部变量 print(a) # a3 8,在inner的局部作用域中找到了a3 inner() # inner()函数结束,a3作为外层变量(outer局部变量)被保留成为a2 print(a) # a2 8,在outer局部作用域中找到a2(在inner中被改变) outer() # outer()函数结束,a2作为outer局部变量被释放 print(a) # a1 10,在当前模块全局作用域中找到了a1 ''' 输出 8 8 10 '''
如果在外层没有找到变量a,则会继续在再外层寻找,直到全局作用域的下一层为止
a = 10 # a1 当前模块全局变量 def outer2(): a = 9 # a2 outer2作用域局部变量 print(a) # a2 9,还未被a3改变 def outer1(): print(a) # a2 9,在outer1中没找到局部变量a,则寻找外层(outer2)变量a2(还未被a3改变) def inner(): nonlocal a a = 0 # a3 既是inner局部变量,又是再外层outer2作用域变量 print(a) # a3 0, 找到inner局部变量a3 inner() # inner()函数结束,a3作为外层变量(outer2局部变量)被保留成为a2 print(a) # a2 0,在outer1中没找到局部变量a,则寻找外层(outer2)变量a2(被a3改变) outer1() print(a) # a2 0, 在outer1中找到outer1局部变量a2(被a3改变) outer2() print(a) # a1 10,在当前模块全局作用域中找到了a1 ''' 输出 9 9 0 0 0 10 '''
全局变量不是外层变量,不被nonlocal寻找
a = 10 # a1 当前模块全局变量 def outer(): def inner(): nonlocal a # 在当前作用域外层即outer局部作用域中没找到outer局部变量a,outer外层为全局作用域,nonlocal不继续寻找,报错 a = 8 print(a) inner() print(a) outer() print(a) # a1 10,在当前模块全局作用域中找到了a1 ''' 输出 SyntaxError: no binding for nonlocal 'a' found '''
注意:使用global
关键字修饰的变量之前可以并不存在,而使用nonlocal
关键字修饰的变量在嵌套作用域中必须已经存在