本文需要您有Python变量查找的知识,如果您不知道,可以参考上篇博文Python变量查找LEGB原则
构成闭包的条件
- 外函数中定义了内函数
- 内函数使用了外函数的变量
- 外函数的返回值是内函数的引用
以下是一个简单的闭包的定义
def outer():
b = 1
def inner(): #外部函数内定义了内部函数
print(b) #内部函数使用了外部函数的变量
return inner #外部函数的返回值是内函数的引用
使用
a = outer()
a() #1
我们先是调用了外部函数outer()
将其返回值赋值给了a
变量,那么a变量实际上是指向的内部函数inner
,当我们调用a
时,相当于调用了inner
,然后打印了外部变量b的值。
似乎没什么不妥
但是,我们知道,函数中的局部变量,在函数结束时会释放掉,但是上例中,执行a()
的时候outer()
已经退出了,那么对应的b也就释放了,但是inner
还调用了b
变量,这就是闭包。
闭包变量是如何使用的?
实际上,解释器会将内函数中使用的外函数变量绑定给内函数,看代码:
def outer():
a = 10
def inner():
print(a)
print(locals()) #{'a': 10}
return inner
outer()()
对变量的修改
这个也是分情况,可变及不可变:
可变变量
def outer():
a = []
def inner():
print(a)
a.append(1)
print(locals())
return inner
outer()()
没任何问题。
再看看不可变变量
def outer():
a = 10
def inner():
print(a) #UnboundLocalError: local variable 'a' referenced before assignment
a = 20
print(locals())
return inner
outer()()
可见和和上篇博文中的情况一样,但是这次的解决方法不是global
而是nonlocal
声明。
def outer():
a = 10
def inner():
nonlocal a
print(a)
a = 20
print(locals())
return inner
outer()()
那么闭包有什么作用的,答案是装饰器,我们下节详细讨论。