要想理解闭包的概念,先理解外函数和内函数的概念。
在一个函数内定义另一个函数,如下:
# 函数中定义另一个函数
def outer():
def inner():
return 0
return 0
其中,outer() 就是外函数,inner() 就是内函数。理解这个概念后,下面就介绍闭包的概念。再看下面的代码:
# 一个函数中定义了另一个函数,并且内函数引用了外函数的参数
def outer(a):
def inner():
n = a
return n
return inner
上面代码可以看出,外函数有一个参数 a, 内函数中引用了该参数,并且外函数返回值是内函数。在外函数中定义了一个内函数,内函数使用了外函数的参数和局部变量,并且外函数返回的是内函数,这时,外函数的参数和局部变量都保留在了内函数中。这种结构就是闭包结构。
有一点需要注意的是,内函数如果引用外函数的参数和局部变量,是可以正常使用的。但是如果内函数想要修改外函数的局部变量,那么PyCharm会报错,报错信息如下:
这时如果想要改变外函数的局部变量,要用到一个关键字 nonlocal。使用方法如下:
# nonlocal的使用,注意这段代码仅仅适用于举例,没有任何实际意义
def outer(a):
b = 5
def inner():
nonlocal b
b = a
return b
return inner
将b在内函数中声明,表示这个变量不是该变量空间的变量,需要向上一层变量空间找这个变量。
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。 看个例子:
# 返回闭包时引用循环变量
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
# 结果: 9 9 9
全部都是9!原因就在于返回的函数引用了变量 i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。