文章背景: Python中的变量,存在相应的作用域。根据作用域的不同,主要有局部变量
、全局变量
和非局部变量
。关键字global
用于定义全局变量,而关键字nonlocal
用于定义非局部变量。
本文在查阅相关资料的基础上,对局部变量、全局变量和非局部变量进行了介绍,还对关键字global
和nonlocal
的使用场景进行了梳理。
1 局部变量
2 全局变量
3 非全局变量
在函数体内或局部范围内声明的变量称为局部变量
。
(1) 通常,我们在函数内部声明一个变量以创建局部变量。
def foo():
y = "local"
print(y)
foo()
运行结果:
local
(2) 在函数外访问局部变量,程序将报错。
def foo():
y = "local"
foo()
print(y)
运行结果:程序报错。
NameError: name 'y' is not defined
局部变量只在函数foo()或局部范围内工作。
在函数外部或全局范围内声明的变量称为全局变量
。这意味着可以在函数内部或外部访问全局变量。
Python中global关键字的基本规则是:
c = 1 # 全局变量
def add():
print(c)
add()
运行结果:
1
(2) 从函数内部修改全局变量
c = 1 # 全局变量
def add():
c = c + 2 # increment c by 2
print(c)
add()
运行结果:程序报错。
UnboundLocalError: local variable 'c' referenced before assignment
因为我们只能访问全局变量,而不能从函数内部对其进行修改。若要在函数内部修改,需要使用global
关键字。
c = 1 # 全局变量
def add():
global c
c = c + 2 # increment c by 2
print(c)
add()
print("c =", c)
运行结果:
3
c = 3
(3) 在嵌套函数中的全局变量
x = 5
def foo():
x = 20
def bar():
global x
x = 25
print("在调用bar之前: ", x)
print("调用bar")
bar()
print("在调用bar之后: ", x)
foo()
print("x在主体内: ", x)
运行结果:
在调用bar之前: 20
调用bar
在调用bar之后: 20
x在主体内: 25
存在同名变量时,python引用变量的顺序为:当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量。
在调用函数bar()的前后,由于函数foo()中,局部变量x的存在,变量x接受局部变量的值,即x =20。此外,在函数bar()中,我们使用了global关键字创建了全局变量,因此,函数内部对x的修改,也会体现到函数foo()以外。所以,在调用函数foo()之后,x=25。
如果将函数foo()内的代码行x = 20
去掉。修改后的代码块如下:
x = 5
def foo():
def bar():
global x
x = 25
print("在调用bar之前: ", x)
print("调用bar")
bar()
print("在调用bar之后: ", x)
foo()
print("x在主体内: ", x)
运行结果:
在调用bar之前: 5
调用bar
在调用bar之后: 25
x在主体内: 25
在函数bar()中,我们使用了global
关键字创建了全局变量。函数bar()内部对x的修改,也会体现到函数foo()内部。
(1) 非全局变量,通过关键字nonlocal
来定义。只在闭包里面生效,作用域就是闭包里面的,外函数和内函数都影响,但是闭包外面不影响。
x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
运行结果:
inner: 2
outer: 2
global: 0
在函数inner()内,我们使用了nonlocal
关键字创建了非局部变量。函数inner()内部对x的修改,体现到了函数内部和函数outer()的内部,但函数outer()的外部不受影响。
(2) nonlocal
的作用范围仅对于所在子函数的上一层函数中拥有的局部变量,必须在上层函数中已经定义过,并且不是非全局变量,否则报错。Nonlocal variable must be bound in an outer function scope.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
test = make_counter()
print(test())
print(test())
运行结果:
1
2
在函数counter()内,我们使用了nonlocal
关键字创建了非局部变量。
针对代码行test = make_counter()
,这里将函数名counter赋给了变量test
。因此,代码test()
,本质上运行的是counter()
。第一次运行test(),返回的count值是1。第二次运行test(),返回count值是2。
参考资料:
[1] Python 全局,局部和非局部变量(https://www.cainiaojc.com/python/python-global-local-nonlocal-variables.html)
[2] Python Global 关键字(https://www.cainiaojc.com/python/python-global-keyword.html)
[3] python关键字nonlocal和global的区别(https://www.jianshu.com/p/ab69b83a8d8a)
[4] python nonlocal 和 global 的区别(https://www.cnblogs.com/kongzhongqijing/articles/14666653.html)