谈起闭包想必大家或多或少都有些头大吧。
什么是闭包:
闭包就是在一个外函数定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了闭包。
我们看一个小小的例子:
def outer(a): #外函数
b = 10
def inner(): #内函数
print(a+b) #在内函数中用到了外函数的临时变量
return inner #外函数的返回值是内函数的引用
demo = outer(6) #demo存了外函数的返回值,也就是inner的引用,相当于执行inner函数
demo() #16
demo2 = outer(10)
demo() #20
#外函数结束时发现内部函数将会调用自己的临时变量,这两个临时变量就不会被释放。但是只能引用不能改变a,b的值
上面这个例子就是一个很简单却又很典型的闭包函数。
使用闭包时内部不能修改外部函数的局部变量:在上代码吧
def outer():
m = 1
def inner():
m = 0
print(m)
print(m)
inner()
print(m)
return inner
result = outer()
result()
1
0
1
0
#我么发现m的值不是所谓的 1 0 0 0而是 1 0 1 0所以inner函数不能改变外部函数的值。
这个例子就是形象的说明 那么在列举在python闭包中经典的错误例子:
def outer():
a = 6
def inner():
a = a+1
return inner
result = outer()
result()
#将会报错如下:
UnboundLocalError: local variable 'a' referenced before assignment
错误的原因是啥呢?
在闭包inner()函数中,变量a在赋值符号‘=’的左面,被python认为是inner()函数的局部变量,python会在右边找到赋值给a的值,但是没有找到所以报错。那外不函数有a啊为啥a没有值,应为刚才说了内部不能改变外部函数的值,只能引用外部函数的变量。
那么又有问题了,内部函数怎么改变外部函数变量的值呢?
在python2中用到的方法是:把闭包变量改变成可变类型的数据类型,比如列表
def outer(a):
c = [a] #将c变为可变类型列表
def inner():
c[0] +=1 #可以改变c的值
print(c[0])
return inner
result = outer(6)
result()
结果为7
在pyhton3中又添加了一种新的方式:用nonlocal关键字声明一个变量,表明这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。来在看代码!!!
def outer(a):
b = a
def inner():
nonlocal b nonlocal关键之向上一层变量中找变量b
b+=1
print(a+b)
return inner
demo = outer(5)
demo
#结果是11
以上介绍了内部函数如何改变外部函数的变量值的两种方法:
- 把闭包变量改变成可变类型的数据类型(如列表)
- 在内部函数中加入关键子nonlocal
最高要注意一点的是:在闭包过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,但是都在使用同一份闭包变量。看看代码吧
def outer(a):
def inner(b):
nonlocal a
a+=b
ptint(a)
return inner
a = outer(3)
a(4)
a(4)
#结果为
7
11
两次打印的值不同,所以可以知道每次调用inner的时候,使用的闭包变量实际上是同一个。
总结:闭包要满足的条件
- 必须有嵌套函数
- 内部函数引用外部变量
- 外部函数返回这个内部函数
那就这样吧!!!