闭包定义:
在一个外函数中定义了一个内函数,内函数里引用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
我们先来看一个简单的函数:
def outer(a): b = 10 print(a+b)
这个函数定义了一个局部变量b,我们来调用这个函数看一下
>>> outer(5) 15 >>> print(b) Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> print(b) NameError: name 'b' is not defined
可以看到在调用完函数outer后,再打印变量b时,会报变量b没定义。这个我们很容易理解:b是函数outer的一个局部变量,调用函数结束后,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。
我们再来看一个嵌套函数:
def outer(a): b = 10 def inner(): print(a+b) return inner
这个函数的返回值是一个函数对象,也就是inner函数,我们来调用下这个函数
>>> demo = outer(5) # 返回的是inner函数 >>> demo() # 这里就相当于执行inner() 15
看到这里是不是感觉到有点奇怪,执行demo = outer(5)后,就是调用outer函数结束了,按道理说这个时候outer函数内的所有东西都会释放掉,包括局部变量a,b。那么为什么我在执行demo()时,还可以打印出a+b的值呢?
这就是一种特殊情况,按照文章开始处闭包的定义,这个嵌套函数其实就是一个闭包,它有一种特权:如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
我们知道什么是闭包了,也知道在闭包中外函数会把变量绑定到内函数上,那么在内函数中能不能修改外函数的变量呢?
我们来试一下:
def outer(a): b = 10 def inner(): b += 1 print(b) return inner
调用:
>>> demo = outer(5) >>> demo() Traceback (most recent call last): File "<pyshell#47>", line 1, in <module> demo() File "C:UserslmjAppDataLocalProgramsPythonPython361.py", line 4, in inner b += 1 UnboundLocalError: local variable 'b' referenced before assignment
报错,看来是不能直接修改,得想其他办法。
在函数作用域中,我们知道如果要在函数中修改全局变量,有两种方法:
- global 声明全局变量
- 全局变量是可变数据类型
同样,在闭包中也是类似情况,在内函数中想修改外函数绑定到内函数的变量时,也有两种方法:
- 用nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。
- 把外函数变量改成可变类型数据进行修改
def outer(a): b = 10 c = [a] # 把外函数变量修改成列表 def inner(): nonlocal b # nonlocal声明外函数变量 b += 1 c[0] += 1 print(b) print(c[0]) return inner
调用:
>>> demo = outer(5) >>> demo() 11 6