一、Python中global与nonlocal 声明
a=10
def foo():
a=100
return a
#输出在函数foo()内声明的局部变量a
print(‘在函数foo()内声明的局部变量a的值是’ , foo())
#输出在全局命名空间声明的全局变量a
print('在全局命名空间声明的全局变量a的值是' , a)
得到结果
在函数foo()内声明的局部变量a的值是 100
在全局命名空间声明的全局变量a的值是 10
函数中对变量的赋值,变量始终绑定到该函数的局部命名空间,使用global语句可以改变这种行为,如下代码
a=10
def foo():
global a #使用global将变量a绑定到全局命名空间,而不再是函数foo()的局部命名空间
a=100
return a
print foo() #输出 100
print a #输出100
解析名称时首先检查局部作用域,然后由内而外一层层检查外部嵌套函数定义的作用域,如还找不到则搜索全局命名空间和内置命名空间
尽管可以层层向外(上)查找变量,但是python2.x版本只支持函数本级作用域(局部变量)和全局命名空间(global),也就是说内部函数不能给定义在外部函数中的局部变量重新赋值,如下代码想通过内部函数decrement()修改外部函数countdown(start)的局部变量n是不起作用的,因为在make_counter外部函数的局部变量n与counter内部函数的局部变量声明的n是属于各自命名作用域的,两者并不相关,但在counter()内部函数中的n+=1
语句实际是n=n+1
的缩写,调用count()函数时counter内部函数运行至n+=1
赋值符=右边已经使用了未声明的局部变量n,因此会由于counter函数中的局部变量n未声明定义而报错
def make_counter(start):
n = int(start)
def counter():
n += 1
return n
return counter
#定义从1开始计数的函数名为count的计数器函数
count=make_counter(1)
#开始计数
count()
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
count()
File "<pyshell#6>", line 4, in counter
n+=1
UnboundLocalError: local variable 'n' referenced before assignment
python2.x版本中,解决办法是把利用列表或字典等可变对象作为变量容器(python中变量只是对象的引用,变量引用int整型等不可变对象时,变量被重新赋值相当于重新生成对象并更改引用指针,而变量引用list列表等可变对象时,变量被重新赋值会直接修改列表等可变对象的值),列表或字典凭借可变对象引用的特性可直接穿透函数嵌套,如下代码
def make_counter(start):
n = [int(start)]
def counter():
n[0] += 1
return n[0]
return counter
python3.x版本中,有更直接的办法,可使用nonlocal声明变量使本该作为内部函数的局部变量绑定到外部函数命名空间中从而变成外部函数的局部变量,如下代码
def make_counter(start):
n = int(start)
def counter():
nonlocal n
n += 1
return n
return counter
二、Python nonlocal 与 global 关键字解析
nonlocal关键字
首先,要明确nonlocal关键字是定义在闭包里面的。如下代码
x = 0
def outer():
x = 1
def inner():
x = 2
print('inner: ' , x)
#输出内部函数声明的x
inner()
print('outer: ' , x)
#输出外部函数声明的x
outer()
#输出全局命名空间声明的x
print('global' , x)
得到结果
inner: 2
outer: 1
global: 0
现在,在闭包里面加入nonlocal关键字进行声明
x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print('inner: ' , x)
#输出内部函数声明的x
inner()
print('outer: ' , x)
#输出外部函数声明的x
outer()
#输出全局命名空间声明的x
print ('global: ' , x)
得到结果
inner: 2
outer: 2
global: 0
在嵌套函数内,当使用nonlocal时,就声明了该变量不是内部函数inner()的局部变量,而是外部函数outer()的局部变量
x=0
def outer():
x = 1
def midder():
x = 2
def inner():
nonlocal x
x=3
print('inner:' , x)
inner()
print('midder: ' , x)
midder()
print('outer: ' , x)
outer()
print('global' , x)
得到结果
inner: 3
midder:3
outer: 1
global: 0
在多层嵌套函数内,当使用nonlocal时,就声明了该变量不是本级函数inner()的局部变量,而是最接近本级函数的外级函数midder()的局部变量
global关键字
x = 0
def outer():
x = 1
def inner():
global x
x = 2
print('inner: ' , x)
#输出内部函数声明的x
inner()
print('outer: ' , x)
#输出外部函数声明的x
outer()
#输出全局命名空间声明的x
print('global' , x)
得到结果
inner: 2
outer: 1
global: 2
global是对全局命名空间中的变量起作用
总结:nonlocal是绑定的最接近本级函数的外部函数(非全局)的局部变量,global是绑定的全局变量