Python中全局变量、局部变量以及global、nonlocal关键字的用法
1.全局变量和局部变量
前言:
- 全局变量是在整个py文件中声明,全局范围内都可以访问;
- 局部变量是在某个函数中声明的,只能在该函数中调用它,如果试图在超出范围的地方调用,程序就爆掉了
- 如果在函数内部定义与某个全局变量一样名称的局部变量,就可能会导致意外的效果,可能不是你期望的。因此不建议这样使用,这样会使得程序很不健全。
有 4 条法则,来区分一个变量是处于局部作用域还是全局作用域:
- 如果变量在全局作用域中使用(即在所用函数之外),它就总是全局变量。
- 如果在一个函数中,有针对该变量的 global 语句,它就是全局变量。
- 否则,如果该变量用于函数中的赋值语句,它就是局部变量。
- 但是,如果该变量没用用在赋值语句中,它就是全局变量。
阅读 例1,可以更好地理解这些法则,
# 例 1
def test1():
global str1
str1 = 'hello' # 这是全局变量
def test2():
str1 = 'python' # 这是局部变量
def test3():
print(str1) # 这是全局变量
str1 = 42 # 这是全局变量
test1()
print(str1) # out: hello
解释:在 test1() 函数中,str1 是全局 str1 变量,因为在函数的开始处,有针对 str1 变量的 global 语句。在 test2() 函数中,str1 是局部变量,因为在该函数中有针对它的赋值语句。在 test3() 函数中,str1 是全局变量,因为在这个函数中,既没有赋值语句,也没有针对它的 global 语句。
- 在一个函数中,一个变量要么总是局部变量,要么总是全局变量。函数中的代码没有办法先使用名为 str1 的局部变量,稍后又在同一个函数中使用全局变量。
- 如果想在一个函数中修改全局变量中存储的值,就必须对该变量使用 global 语句。
- 在一个函数中,如果试图在局部变量赋值之前就使用它,Python就会报错。如例2
#例 2
def test1():
print(str1) # ERROR
str1 = 'hello world' # 局部变量
str1 = 'hi' # 全局变量
test1()
'''
报错:
File "E:/test/test.py", line 92, in test1
print(str1) # ERROR
UnboundLocalError: local variable 'str1' referenced before assignment
'''
例2解释:之所以报错,因为 Python 看到 test1() 函数中有针对 str1 的赋值语句,所以会认为 str1 变量是局部变量。但是 print(str1) 语句的执行在 str1 赋值之前,局部变量 str1 并不存在(即赋值之前应用本地变量 str1)。Python不会退回使用全局 str1 变量。
2. global语句
使用 global 语句可以在一个函数内修改全局变量。如果在函数内的顶部有 " global str1 "这样的代码,它就告诉 Python ,“在这个函数中,str1 指的是全局变量,所以不要用这个名字创建一个局部变量”。例如下面代码:
def test1():
global str1
str1 = 'one'
str1 = 'global'
test1()
print(str1) # out: one
因为 str1 在 test1() 的顶部被声明 gloabl,所以当 str1 被赋值为 ‘one’ 时,赋值发生在全局作用域的 str1 上。没有创建局部 str1 变量。
3. nonlocal语句
Python 3.0 引入了一条新的nonlocal语句,实际上,当执行到 nonlocal 语句的时候,nonlocal中列出的名称必须在一个嵌套的def中提前定义过,否则,将会产生一个错误。nonlocal名称只能出现在嵌套的def中,而不能在模块的全局作用域中或def之外的内置作用域中。
表示在局部作用域中,调用父级作用域中的变量;如果嵌套了很多层,最多只能作用到最顶层的函数,不能作用于全局变量。
动手算算这些题,理论要和实际相结合
a = 1
def func_1():
a =2
def func_2():
# a = 3 #模块A
def func_3():
nonlocal a
a = 4
print(' 8行:',a)
print(' 9行:',a)
func_3()
print('11行:',a)#2 --> 4
print('12行:',a)
func_2()
print('14行:',a)#2-->4
print('15行:',a)
func_1()
print('17行:',a)#全局变量,nonlocal无权更改
上面代码中,加上模块A的结果:
不加模块A的结果: