如何理解Python中的闭包

闭包的理解基础

闭包解决的是函数嵌套的变量访问问题

非闭包场景

内部函数 inner_fun 可以成功访问外部变量 x

1
2
3
4
5
6
def outer_fun(x):
def inner_fun():
print(x)
inner_fun()

outer_fun(6)

6

如果在内部函数 inner_fun 要修改变量 x 的值,就行不通了

1
2
3
4
5
6
7
def outer_fun(x):
def inner_fun():
x += 1
print(x)
inner_fun()

outer_fun(6)

x += 1
UnboundLocalError: local variable ‘x’ referenced before assignment

这时想修改必须 在内部函数 inner_fun 中声明 nonlocal 变量才行

1
2
3
4
5
6
7
8
def outer_fun(x):
def inner_fun():
nonlocal x
x += 1
print(x)
inner_fun()

outer_fun(6)

7

闭包场景

闭包举例
这里将外部函数 outer_fun 的返回,return 为这个嵌套函数 inner_fun
outer_fun(6) 调用了第一次后,x + 1 = 7
再次调用 outer() 时,记住了这个变量 7

1
2
3
4
5
6
7
def outer_fun(x):
def inner_fun():
print(x + 1)
return inner_fun

outer = outer_fun(6)
outer()

7

注意看 outer = outer_fun(6) 这一行代码,是不是跟类的实例化非常相似呢?
这就是闭包,可以将一些变量数据直接附加到“闭包”里面,
此时这个“闭包”会记住这些变量数据。
好比面向对象的封装一样,把一些属性和变量封装到一个对象类里面

怎么创建一个闭包

首先它得是一个嵌套函数
接着内部函数引用nonlocal变量
最后嵌套函数的返回是内部函数

闭包具体应用简单举例

1
2
3
4
5
6
7
def outer_fun(x):
def inner_fun(y):
print(x + y)
return inner_fun

outer = outer_fun(5)
outer()

TypeError: inner_fun() missing 1 required positional argument: ‘y’

这里会报错,因为内部函数 inner_fun 也要传入一个参数 y

1
2
3
4
5
6
7
8
9
def outer_fun(x):
def inner_fun(y):
print(x + y)
return inner_fun

outer = outer_fun(5)
outer(1)
outer(6)
outer(60)

6
11
65

outer = outer_fun(5) 引用记住了参数 5
outer(1) outer(6) outer(60) 依次执行 + y 的操作

可以看到,当我们使用闭包的时候,
我们不需要定义全局变量,也可以访问到函数内部的数据
(一般情况下函数外部是没有办法访问函数内部的变量数据的),
也就是说可以拿到闭包提供的隐藏数据。

注意看 outer = outer_fun(5) 这一行代码,是不是跟类的实例化非常相似呢?
这样的话,如果我们的某个功能只需要一个函数的话,那么我们就直接写一个闭包,而不用写一个类那么麻烦。

我想,往后我跟你说装饰器的时候,你会更加明白闭包的应用。

总之,Python 中的闭包就像一个包,
这个包的牛逼之处在于,
它可以让我们引用函数中的 nonlocal 变量,
这个包可以隐藏一些变量数据,当我们需要的时候,就可以从这个包获取。

当你发现你要写的类只需要一个方法就能实现的时候,用闭包是一种更好的选择。