函数的作用域、global与nonlocal

时间:2021-07-14 21:46:44

global

表示不再使用局部局部作用域中的内容,而是改用全局作用域中的变量

 a = 100

 def func():
global a # 表示不再局部创建这个变量,而是直接使用这个全局的a
a = 28
print(a) func()
print(a)

执行结果

28
28 Process finished with exit code 0

对于可变的数据类型如列表、字典等也可以使用global

 lst = [1, 2, 3]
dic = {1: 1, 2: 2} def func():
global lst
global dic
lst = [2, 3, 4]
dic = {1: 10, 2: 20}
print(lst)
print(dic) func()
print(lst)
print(dic)

执行结果

[2, 3, 4]
{1: 10, 2: 20}
[2, 3, 4]
{1: 10, 2: 20} Process finished with exit code 0

对于可变数据类型,如果不加global,那么可以追加元素,删除元素,修改元素,但是不能直接赋值(就是不能 lst =[....]),直接赋值的结果是创建一个局部的列表或字典

 lst = ["麻花疼", "刘强东", "雷军军"]
dic = {"马云": "淘宝"} def func():
lst.append("马云云")
# lst = ["马化腾", "雷军"]
lst.remove("刘强东")
dic["强东"] = "京东"
dic["马云"] = "支付宝"
print(lst)
print(dic) func()
print(lst)
print(dic)

执行结果

['麻花疼', '雷军军', '马云云']
{'马云': '支付宝', '强东': '京东'}
['麻花疼', '雷军军', '马云云']
{'马云': '支付宝', '强东': '京东'} Process finished with exit code 0

如果在函数里面直接赋值,结果会是怎么样的呢,来看代码

 lst = ["麻花疼", "刘强东", "雷军军"]
dic = {"马云": "淘宝"} def func():
# lst.append("马云云")
lst = ["马化腾", "雷军"] # 相当于在局部名称空间重新创建一个变量lst指向新列表[...]
# lst.remove("刘强东")
dic["强东"] = "京东" # 直接对全局名称空间的dic进行修改
# dic["马云"] = "支付宝"
print(lst)
print(dic) func()
print(lst)
print(dic)

执行结果

['马化腾', '雷军']
{'马云': '淘宝', '强东': '京东'}
['麻花疼', '刘强东', '雷军军']
{'马云': '淘宝', '强东': '京东'} Process finished with exit code 0

nonlocal

nonlocal表示在局部作用域内,调用父级命名空间中的变量

 a = 10

 def func1():
a = 20 # 局部变量 def func2():
# nonlocal a # 调用func1里面的a(值为20)
a = 30 # 将func1里面a的值改为30
print(a) # 打印30 func2()
print(a) # func1里面a的值已经改为30了,因此打印30,不加nonlocal打印20 func1()
print(a) # 打印全局变量a(值为10)

执行结果

30
30
10 Process finished with exit code 0

综合运用

来看一段代码

a = 1

def func1():
a = 2 def func2():
nonlocal a
a = 3 def func3():
a = 4
print(a)
print(a)
func3()
print(a)
print(a)
func2()
print(a) print(a)
func1()
print(a)

运行结果

1
2
3
4
3
3
1 Process finished with exit code 0

来看分析,注意执行顺序,从上往下,遇到函数定义跳过,遇到函数调用时跳转到函数定义,函数体执行完接着之前的位置执行。

a = 1      # 创建全局变量a(值为1)

def func1():
a = 2 # 创建局部变量a def func2():
nonlocal a # 调用func1(父级命名空间)里面的a
a = 3 # 把func1里面a的值改为3 def func3():
a = 4 # 创建局部变量a
print(a) # 打印func3里面局部变量a的值4-----4
print(a) # 打印func2里面的a的值3------3
func3()
print(a) # 打印func2里面的a的值3(func3里面的a不影响func2的a)------5
print(a) # 打印func1里的局部变量a的值2------2
func2()
print(a) # 打印func1里面的a的值3(func1里面的a已经被func2改成了3)-------6 print(a) # 打印全局变量a的值1------------1
func1() # 跳转到func1定义的位置
print(a) # 打印1---------7

总结

(1)调用变量是要搞清楚变量是全局变量还是局部变量,如果是局部变量的话是属于哪个函数的,它能否被其子函数调用

(2)注意代码的执行顺序,代码从上往下执行,遇到函数定义跳过,等到遇到函数调用时才跳转到定义的部分开始执行,执行完了后再跳转到函数调用的地方