Python:global、local与nonlocal变量
1 local和global变量
先来看一个最简单的Python程序例子:
import numpy as np
n = 2
def func(a):
b = 1
return a + b
print(func(n)) # 3
这里b
声明在函数func
内,则该变量拥有一个local scope(局部作用域,即在函数内),我们将这类变量称为local(局部)变量。
与之相对的np
和n
这两个变量都在函数之外声明,也即它们都在gobal scope(全局作用域)中,我们将它们global(全局)变量。
如果我们使用IDE在return a+b
处打断点并调试,那么可以看到IDE很方便地为我们展示了当前的局部和全局变量(以VSCode为例):
我们在local scope内也可以对global变量进行读取,如下所示:
n = 2
def func(a):
b = 1
return a + b + n # 对全局变量进行读取
print(func(n)) # 5
然而,如果在local scope内对global变量进行修改,比如这样写:
n = 2
def func(a):
n += 1 # 对全局变量进行修改
b = 1
return a + b + n
print(func(n))
运行到n+=1
这一语句是就会抛出异常:
UnboundLocalError: local variable 'n' referenced before assignment
此时我们需要用global
关键字在局部作用域内声明一个global变量,然后就可以自由修改该变量了:
n = 2
def func(a):
global n
n += 1
b = 1
return a + b + n
print(func(n)) # 6
2 nonlocal 变量
最后,我们还要提一种变量,叫nonlocal变量。这种变量常用在局部嵌套函数中将外层函数中的自由变量绑定到内层函数作用域(事实上外层函数中的自由变量对于内层函数来说既也非local也非global,故名nonlocal)。如下列所示:
# outside function
def outer():
message = 'local'
# nested function
def inner():
# declare nonlocal variable
nonlocal message
message = 'nonlocal'
print("inner:", message)
inner()
print("outer:", message)
outer()
打印输出:
inner: nonlocal
outer: nonlocal
可以看到,nonlocal
的使用将外层函数作用域中的自由变量message
和内层函数的作用域进行了绑定。
不过需要注意的是,如果我们使用global
关键字来声明变量:
# outside function
def outer():
message = 'local'
# nested function
def inner():
# declare global variable
global message
message = 'nonlocal'
print("inner:", message)
inner()
print("outer:", message)
outer()
那么最终的打印输出结果为:
inner: nonlocal
outer: local
这是因为global
关键字的使用让我们在inner()
函数(局部作用域)内声明了一个global变量,故如果我们在inner()
函数内做任何修改,则修改的结果只会在局部作用域(也即outer()
函数)之外出现。
此外,nonlocal
还可以用来构建如下列所示的闭包函数func
(参见我的博客《Python技法4:闭包和保存自由变量 》):
def sample():
n = 0
# 闭包函数
def func():
nonlocal n
n += 1
print("n =", n)
return func
f = sample()
f() # n = 1
f() # n = 2
这里也是通过nonlocal
关键字将自由变量与内层函数绑定,然后再对其进行修改的。